Topcoder--SRM570Div1--1000--CurvyonRails
巨强的一道题
对于可行解的判定,考虑对于每个城市都会有两个铁路断点,而每个铁路断点必须和另一个铁路断点结合,而棋盘图又是天然二分图,所以第一阶段考虑判断可行解的建图方式为: 棋盘黑白染色,源点向所有白点连边,所有黑点向汇点连边,容量均为2.然后所有白点向相邻黑点连容量为1点边,如果跑出最大流使源汇均满流则原图有解。
至此容易观察到如果可行,黑白点数量必然相同,且流量为黑点数*2。
之后为了解决题目中的第二个问题,我们考虑如果能将问题转化到费用流上面就会很清真。
怎么转化为费用流呢?
因为曲线有4种情况而直线只有2种,所以考虑计算直线费用。
首先可以看出如果走的是直线,那么对于一个方格内的铁路必然均链接横向或均链接纵向,那么我们把所有有小动物的点拆出两个点,分别代表匹配橫行和匹配纵行,然后对于两个可匹配度都匹配相同方向的就可以轻松统计了。
具体建图看代码吧
代码(无费用流部分):
int p[30][30],n,m,fix,fix2,mk[30][30],sz; int wt,bl; int getmin(vector<string> field) { S=MAXN-2;T=MAXN-3;cnt=1; n=field.size();m=field[0].size(); fix=n*m;fix2=fix<<1; for(int i=0;i<n;i++) for(int j=0;j<m;j++) p[i+1][j+1]=field[i][j]=='.'?1:(field[i][j]=='C'?2:0); for(int t,i=1;i<=n;i++) for(int j=1;j<=m;j++) { mk[i][j]=++sz; if(!p[i][j]) continue; t=(i+j)&1; if(t) { insert(S,mk[i][j],2,0,1);wt++; } else { insert(mk[i][j],T,2,0,1);bl++; } if(p[i][j]==1) { insert(mk[i][j],mk[i][j]+fix,2,0,t); insert(mk[i][j],mk[i][j]+fix2,2,0,t); } else { insert(mk[i][j],mk[i][j]+fix,1,0,t); insert(mk[i][j],mk[i][j]+fix,1,1,t); insert(mk[i][j],mk[i][j]+fix2,1,0,t); insert(mk[i][j],mk[i][j]+fix2,1,1,t); } } for(int t,i=1;i<=n;i++) for(int j=1;j<=m;j++) { t=(i+j)&1;if(!t) continue; if(p[i-1][j]) insert(mk[i][j]+fix,mk[i-1][j]+fix,1,0,1); if(p[i+1][j]) insert(mk[i][j]+fix,mk[i+1][j]+fix,1,0,1); if(p[i][j-1]) insert(mk[i][j]+fix2,mk[i][j-1]+fix2,1,0,1); if(p[i][j+1]) insert(mk[i][j]+fix2,mk[i][j+1]+fix2,1,0,1); } MSMF(); if(bl!=wt||flow!=bl*2) return -1; return cost; }