首页 > 洛谷P3159 [CQOI2012]交换棋子

洛谷P3159 [CQOI2012]交换棋子

巧妙的拆点方式,首先把1看成黑点,0看成空的,几次交换就可以看成一条路径

1)从容量上看,这条路径为1-2-2-2-2-2-……-2-1

2)从费用上看,这条路径每条边费用都是1

于是用一种巧妙的拆点方式,把一个点拆成三个,连两条边,成为一条链,

然后如果是黑点的话就由s向中间那个点连边,如果是路过的话就由一条链的尾部向另一条链的首部连边

这样就满足了上面的条件1)2)

容量的话如果是黑点出来就是(c+1)/2,进来是c/2,其他的以此类推

  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 #define rint register int
  8 #define ll long long
  9 #define MAXN 2000+10
 10 #define pb push_back
 11 #define INF 0x7f7f7f7f
 12 #define oo 0x7f7f7f7f7f7f7f7f
 13 #define pil pair
 14 #define mp make_pair
 15 using namespace std;
 16 int read(){
 17     int x=0,f=1;char ch=getchar();
 18     while(ch<'0'||ch>'9'){ if('-'==ch)f=-1;ch=getchar();}
 19     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
 20     return x*f;
 21 }
 22 struct E{
 23     int from,to,cap,flow;
 24     ll cost;
 25     E(int x=0,int y=0,int c=0,int f=0,ll w=0LL){
 26         from=x,to=y,cap=c,flow=f,cost=w;
 27     }
 28 };
 29 struct Dinic{
 30     int n,m,s,t;
 31     vector es;
 32     vector<int> G[MAXN];
 33     void init(int n,int s,int t){
 34         this->n=n;
 35         this->s=s,this->t=t;
 36         es.clear();
 37         for(int i=0;i<=n;i++)G[i].clear();
 38     }
 39     void add(int x,int y,int cap,ll cost){
 40         es.pb(E(x,y,cap,0,cost));
 41         es.pb(E(y,x,0,0,-cost));
 42         m=es.size();
 43         G[x].pb(m-2),G[y].pb(m-1);
 44     }
 45     int p[MAXN],a[MAXN];
 46     ll d[MAXN];
 47     int b[MAXN];
 48     bool SPFA(int &flow,ll &cost){
 49         p[s]=0,a[s]=INF;
 50         memset(d,0x7f,sizeof(d));
 51         d[s]=0;
 52         memset(b,0,sizeof(b));
 53         b[s]=1;
 54         queue<int> q;
 55         q.push(s);
 56         while(!q.empty()){
 57             int x=q.front();q.pop();b[x]=0;
 58             for(rint i=0;i){
 59                 E &e=es[G[x][i]];
 60                 if(e.cap>e.flow&&d[e.to]>d[x]+e.cost){
 61                     p[e.to]=G[x][i];
 62                     a[e.to]=min(a[x],e.cap-e.flow);
 63                     d[e.to]=d[x]+e.cost;
 64                     if(!b[e.to]){
 65                         b[e.to]=1;
 66                         q.push(e.to);
 67                     }
 68                 }
 69             }
 70         }
 71         if(oo==d[t]){
 72             return 0;
 73         }
 74         flow+=a[t];
 75         cost+=a[t]*d[t];
 76         for(rint i=t;i!=s;i=es[p[i]].from){
 77             es[p[i]].flow+=a[t];
 78             es[p[i]^1].flow-=a[t];
 79         }
 80         return 1;
 81     }
 82     pil MaxfMinc(){
 83         int flow=0;
 84         ll cost=0LL;
 85         while(SPFA(flow,cost));
 86         return mp(flow,cost);
 87     }
 88 }D;
 89 int n,m,s=0,t=MAXN-1;
 90 int id[3][25][25];
 91 int a[25][25],b[25][25],p[25][25];
 92 int cnt1=0,cnt2=0;
 93 void init(){
 94     n=read();m=read();
 95     D.init(t,s,t);
 96     char c[25];
 97     for(rint i=1;i<=n;i++){
 98         for(rint j=1;j<=m;j++){
 99             id[0][i][j]=(i-1)*m+j;
100         }
101     }
102     for(rint k=1;k<=2;k++){
103         for(rint i=1;i<=n;i++){
104             for(rint j=1;j<=m;j++){
105                 id[k][i][j]=id[k-1][i][j]+n*m;
106             }
107         }
108     }
109     for(rint i=1;i<=n;i++){
110         scanf("%s",c+1);
111         for(rint j=1;j<=m;j++){
112             a[i][j]=c[j]-'0';
113         }
114     }
115     for(rint i=1;i<=n;i++){
116         scanf("%s",c+1);
117         for(rint j=1;j<=m;j++){
118             b[i][j]=c[j]-'0';
119         }
120     }
121     for(rint i=1;i<=n;i++){
122         for(rint j=1;j<=m;j++){
123             if(a[i][j]&&b[i][j]){
124                 a[i][j]=b[i][j]=0;
125             }    
126             else if(a[i][j]){
127                 cnt1++;
128             }
129             else if(b[i][j]){
130                 cnt2++;
131             }
132         }
133     }
134     for(rint i=1;i<=n;i++){
135         scanf("%s",c+1);
136         for(rint j=1;j<=m;j++){
137             p[i][j]=c[j]-'0';
138         }
139     }
140 }
141 void add(int x,int y,int c1,int c2){
142     D.add(id[0][x][y],id[1][x][y],c1,0);
143     D.add(id[1][x][y],id[2][x][y],c2,0);
144 }
145 void solve(){
146     int dx[8]={ 0,0,-1,1,-1,-1,1,1};
147     int dy[8]={ 1,-1,0,0,-1,1,-1,1};
148     for(rint i=1;i<=n;i++){
149         for(rint j=1;j<=m;j++){
150             if(a[i][j]){
151                 add(i,j,p[i][j]>>1,(p[i][j]+1)>>1);
152                 D.add(s,id[1][i][j],1,0);
153             }
154             else if(b[i][j]){
155                 add(i,j,(p[i][j]+1)>>1,p[i][j]>>1);
156                 D.add(id[1][i][j],t,1,0);
157             }
158             else{
159                 add(i,j,(p[i][j]+1)>>1,p[i][j]>>1);                
160             }
161             for(rint k=0;k<8;k++){
162                 int x=i+dx[k],y=j+dy[k];
163                 if(1<=x&&x<=n&&1<=y&&y<=m){
164                     D.add(id[2][i][j],id[0][x][y],INF,1);
165                 }
166             }
167         }
168     }
169     pil ans=D.MaxfMinc();
170     if(ans.first!=cnt1||cnt1!=cnt2){
171         printf("-1
");
172     }
173     else{
174         printf("%d
",ans.second);
175     }
176 }
177 int main()
178 {
179     init();
180     solve();
181     return 0;
182 }

 

转载于:https://www.cnblogs.com/w-h-h/p/8453004.html

更多相关:

  •         Apache POI是一个开源的利用Java读写Excel,WORD等微软OLE2组件文档的项目。        我的需求是对Excel的数据进行导入或将数据以Excel的形式导出。先上简单的测试代码:package com.xing.studyTest.poi;import java.io.FileInputSt...

  • 要取得[a,b)的随机整数,使用(rand() % (b-a))+ a; 要取得[a,b]的随机整数,使用(rand() % (b-a+1))+ a; 要取得(a,b]的随机整数,使用(rand() % (b-a))+ a + 1; 通用公式:a + rand() % n;其中的a是起始值,n是整数的范围。 要取得a到b之间的...

  • 利用本征图像分解(Intrinsic Image Decomposition)算法,将图像分解为shading(illumination) image 和 reflectance(albedo) image,计算图像的reflectance image。 Reflectance Image 是指在变化的光照条件下能够维持不变的图像部分...

  • 题目:面试题39. 数组中出现次数超过一半的数字 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入: [1, 2, 3, 2, 2, 2, 5, 4, 2] 输出: 2 限制: 1 <= 数组长度 <= 50000 解题: cl...

  • 题目:二叉搜索树的后序遍历序列 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。 参考以下这颗二叉搜索树:      5     /    2   6   /  1   3示例 1: 输入: [1,6,3,2,5] 输出...

  • 用python编写乘法口诀表的方法 发布时间:2020-08-25 11:46:35 来源:亿速云 阅读:60 作者:小新 用python编写乘法口诀表的方法?这个问题可能是我们日常学习或工作经常见到的。希望通过这个问题能让你收获颇深。下面是小编给大家带来的参考内容,让我们一起来看看吧! 第一种:使用for遍历循环嵌套for x in...

  • //很长一段时间我都只使用以下方式做数组循环,具体原因看数据 var aa = for (var i = 0, l = aa.length; i < l; i++) { var a = aa[i];} 数据采集图片来源于网友 很明显,for循环第二种方式完胜!!! 至于for in、forEach什么的,不知道甩他们多少...

  • 目录 1. Scene Graph Generation with External Knowledge and Image Reconstruction 2. Knowledge Acquisition for Visual Question Answering via Iterative Querying Author...

  • 基础题1: 输入一个正整数 n (1≤n≤10)和n 阶方阵a的元素,如果方阵a中的所有元素都沿主对角线对称,输出“Yes”, 否则,输出“No”。主对角线为从矩阵的左上角至右下角的连线,方阵a中的所有元素都沿主对角线对称指对所有i, k,a[i][k]和a[k][i]相等。输入输出示例如下: 输入: 3 1 2 3 4 5 6 7...

  • 程序流程控制 分支 顺序 循环 if switch&case 1 2 3 调整 break 1.6 前 switch(byte、short、char、int) 1.7 可放String 循环 while(次数不确定) do while for(确定次数) break(跳出本层循环) continue(跳出本次循环)     *   2...