zoukankan      html  css  js  c++  java
  • P3159 [CQOI2012]交换棋子

    思路

    相当神奇的费用流拆点模型
    最开始我想到把交换黑色棋子看成一个流流动的过程,流从一个节点流向另一个节点就是交换两个节点,然后把一个位置拆成两个点限制流量,然后就有了这样的建图方法
    S向所有初始是黑色点的入点连cap=1,cost=0的边,最后是黑色点的出点向T连一条cap=1,cost=0的边,然后对应点的出点向它八连通的点的入点连一条cap=INF,cost=1的边,每个点的入点向出点连一条cap=limit,cost=0的边
    看起来很靠谱,实际是假的
    因为我们刚才的方法没有考虑到一条交换路径的两个端点只交换一次并且路径上其他点都交换了两次(也就是端点和路径上的其他点没有区别)
    所以可以拆成三层图。
    S向每个初始黑点的mid连边,每个最终黑点的mid向T连边,相邻点连边不变,
    然后懒得讲了。。。。

    代码

    ···cpp

    include

    include

    include

    include

    include

    using namespace std;
    struct Edge{
    int u,v,cap,cost,flow;
    };
    const int MAXN = 1550;
    const int INF = 0x3f3f3f3f;
    vector edges;
    vector G[MAXN];
    int d[MAXN],p[MAXN],a[MAXN],vis[MAXN],s,t,n,m;
    queue q;
    void addedge(int u,int v,int cap,int cost){
    edges.push_back((Edge){u,v,cap,cost,0});
    edges.push_back((Edge){v,u,0,-cost,0});
    int cnt=edges.size();
    G[u].push_back(cnt-2);
    G[v].push_back(cnt-1);
    }
    bool spfa(int &cost,int &flow){
    memset(d,0x3f,sizeof(d));
    memset(p,0,sizeof(p));
    q.push(s);
    d[s]=0;
    a[s]=INF;
    p[s]=0;
    vis[s]=true;
    while(!q.empty()){
    int x=q.front();
    q.pop();
    vis[x]=false;
    for(int i=0;i<G[x].size();i++){
    Edge &e = edges[G[x][i]];
    if(e.cap>e.flow&&d[x]+e.cost<d[e.v]){
    d[e.v]=d[x]+e.cost;
    p[e.v]=G[x][i];
    a[e.v]=min(a[x],e.cap-e.flow);
    if(!vis[e.v]){
    vis[e.v]=true;
    q.push(e.v);
    }
    }
    }
    }
    if(d[t]INF)
    return false;
    flow+=a[t];
    cost+=a[t]d[t];
    for(int i=t;i!=s;i=edges[p[i]].u){
    edges[p[i]].flow+=a[t];
    edges[p[i]^1].flow-=a[t];
    }
    return true;
    }
    void MCMF(int &cost,int &flow){
    cost=flow=0;
    while(spfa(cost,flow));
    }
    inline int id(int x,int y){
    return (x-1)
    m+y;
    }
    char S[50];
    int pre_map[30][30],bac_map[30][30];
    int main(){
    s=MAXN-2;
    t=MAXN-3;
    int cntb1=0,cntb2=0;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++){
    scanf("%s",S+1);
    for(int j=1;j<=m;j++){
    if(S[j]
    '0'){
    cntb1++;
    addedge(s,id(i,j)+2nm,1,0);
    }
    pre_map[i][j]=S[j]-'0';
    }
    }
    for(int i=1;i<=n;i++){
    scanf("%s",S+1);
    for(int j=1;j<=m;j++){
    if(S[j]'0'){
    cntb2++;
    addedge(id(i,j)+2nm,t,1,0);
    }
    bac_map[i][j]=S[j]-'0';
    }
    }
    if(cntb1!=cntb2){
    printf("%d ",-1);
    return 0;
    }
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++){
    if(i!=1){//up
    addedge(id(i,j)+nm,id(i-1,j),INF,1);
    }
    if(j!=1){//left
    addedge(id(i,j)+n
    m,id(i,j-1),INF,1);
    }
    if(i!=n){//down
    addedge(id(i,j)+nm,id(i+1,j),INF,1);
    }
    if(j!=m){//right
    addedge(id(i,j)+n
    m,id(i,j+1),INF,1);
    }
    if(i!=1&&j!=1){//zuoshang
    addedge(id(i,j)+nm,id(i-1,j-1),INF,1);
    }
    if(i!=n&&j!=1){//zuoxia
    addedge(id(i,j)+n
    m,id(i+1,j-1),INF,1);
    }
    if(i!=1&&j!=m){//youshang
    addedge(id(i,j)+nm,id(i-1,j+1),INF,1);
    }
    if(i!=n&&j!=m){//youxia
    addedge(id(i,j)+n
    m,id(i+1,j+1),INF,1);
    }
    }
    for(int i=1;i<=n;i++){
    scanf("%s",S+1);
    for(int j=1;j<=m;j++){
    if(pre_map[i][j]
    1&&bac_map[i][j]0){
    addedge(id(i,j),id(i,j)+2nm,(S[j]-'0'+1)/2,0);
    addedge(id(i,j)+2nm,id(i,j)+n*m,(S[j]-'0')/2,0);
    }
    if(pre_map[i][j]
    0&&bac_map[i][j]1){
    addedge(id(i,j),id(i,j)+2nm,(S[j]-'0')/2,0);
    addedge(id(i,j)+2nm,id(i,j)+n*m,(S[j]-'0'+1)/2,0);
    }
    if(pre_map[i][j]
    bac_map[i][j]){
    addedge(id(i,j),id(i,j)+2nm,(S[j]-'0')/2,0);
    addedge(id(i,j)+2nm,id(i,j)+n*m,(S[j]-'0')/2,0);
    }
    }
    }
    int cost=0,flow=0;
    MCMF(cost,flow);
    printf("%d ",cost);
    return 0;
    }

    ···

  • 相关阅读:
    第零次作业
    第一本书的学习笔记
    第一次作业
    第零次作业
    第一周作业
    第零次作业回复
    第零次作业
    第一周作业
    第0次作业
    第一次作业
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10491843.html
Copyright © 2011-2022 走看看