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;
    }

    ···

  • 相关阅读:
    ACM-ICPC 2018 徐州赛区网络预赛 F Features Track(STL模拟)
    ACM-ICPC 2018 徐州赛区网络预赛 H Ryuji doesn't want to study (树状数组差分)
    数位dp
    Number String
    The King’s Ups and Downs
    容斥定理
    Anagram(山东省2018年ACM浪潮杯省赛)
    STL——queue
    lower_bound和upper_bound使用说明
    int string相互转换
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10491843.html
Copyright © 2011-2022 走看看