题目(bzoj)
题目(洛谷)
这题明显是费用流......
建模方法:
将每个格子拆成两个点,分别为“入点”和“出点”,分别表示进入这个格子以及出去这个格子,中间接一条边,费用为0.
然后这个流量嘛......
分成两种情况:
1.当前格子初末状态相同,则流量为m[i][j]/2;
2.当前格子初末状态不同,则流量为(m[i][j]+1)/2。
这个其实很好理解:初末状态相同,那么肯定有一次交换将当前格子交换进来并且不出去;初末状态不相同,那么肯定有一次交换将当前格子交换进来并且交换出去。
然后,每个格子向相邻格子接边,流量为INF,费用为1。
S向每个格子的“入点”接一条边,流量为1,费用为0;每个格子的“出点”向T接一条边,流量为1,费用为0。
最后跑一遍费用流,完毕。
另外注意特判:若最大流+初末状态相同且为白点的格子数!=所有白点格子数,则无解。
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <vector> #include <climits> #include <cctype> #include <cstdlib> #define ll long long #define llmax LONG_LONG_MAX #define llmin LONG_LONG_MIN #include <ext/rope> #include <ext/pb_ds/assoc_container.hpp> #define maxn 2050 using namespace std; using namespace __gnu_cxx; using namespace __gnu_pbds; template <class _E> inline void read(_E &e) { e=0;bool ck=0;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')ck=1;ch=getchar();} while(ch>='0'&&ch<='9'){e=e*10+ch-'0';ch=getchar();} if(ck)e=-e; } const int INF=0x3f3f3f3f; inline void input(); struct edge{ int u,v,cap,flow,cost; }; struct Answer{ int flow,cost; }Ans; struct mcmf{ int n,m; vector <edge> edges; vector <int> g[maxn]; int d[maxn],p[maxn],inq[maxn],a[maxn]; inline void init(int n) { this->n=n; for (int i=0;i<n;++i) g[i].clear(); edges.clear(); } inline void ad(int u,int v,int cap,int cost) { edges.push_back((edge){u,v,cap,0,cost}); edges.push_back((edge){v,u,0,0,-cost}); m=edges.size(); g[u].push_back(m-2);g[v].push_back(m-1); } inline bool spfa(int s,int t,int &flow,int &cost) { memset(d,INF,sizeof d); memset(inq,0,sizeof inq); d[s]=0;inq[s]=1;p[s]=0;a[s]=INF; queue <int> q; q.push(s); while (!q.empty()) { int u=q.front();q.pop(); inq[u]=0; int siz=g[u].size(); for (int i=0;i<siz;++i) { edge &e=edges[g[u][i]]; if (e.cap>e.flow && d[e.v]>d[u]+e.cost) { d[e.v]=d[u]+e.cost; p[e.v]=g[u][i]; a[e.v]=min(a[u],e.cap-e.flow); if (!inq[e.v]) q.push(e.v),inq[e.v]=1; } } } if (d[t]==INF) return false; flow+=a[t]; cost+=a[t]*d[t]; int u=t; while (u!=s) { edges[p[u]].flow+=a[t]; edges[p[u]^1].flow-=a[t]; u=edges[p[u]].u; } return true; } Answer mincost(int s,int t) { int flow=0,cost=0; while (spfa(s,t,flow,cost)); return (Answer){flow,cost}; } }mc; int n,m,t1,t2; int cnt[25][25]; int st[25][25],en[25][25]; char ss[25]; int dx[]={-1,0,1,-1,1,1,-1,0,1}; int dy[]={1,1,1,0,0,-1,-1,-1}; int main() { input(); int S=3*n*m+5;int T=S+1; int N=n*m+3; mc.init(T+5); for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) { if (st[i][j]==1 && en[i][j]==0) { mc.ad(S,(i-1)*m+j,1,0); mc.ad((i-1)*m+j,(i-1)*m+j+N,(cnt[i][j]+1)/2,0); } else if (st[i][j]==0 && en[i][j]==1) { mc.ad((i-1)*m+j,T,1,0); mc.ad((i-1)*m+j,(i-1)*m+j+N,(cnt[i][j]+1)/2,0); } else mc.ad((i-1)*m+j,(i-1)*m+j+N,cnt[i][j]/2,0); for (int k=0;k<8;++k) { int nx=i+dx[k],ny=j+dy[k]; if (nx<1||ny<1||nx>n||ny>m) continue; mc.ad((i-1)*m+j+N,(nx-1)*m+ny,INF,1); } } Ans=mc.mincost(S,T); if ((Ans.flow+t2)==t1) printf( else puts("-1"); return 0; } inline void input() { read(n),read(m); for (int i=1;i<=n;++i) { scanf( for (int j=1;j<=m;++j) { st[i][j]=ss[j]-'0'; if (st[i][j]==1) ++t1; } } for (int i=1;i<=n;++i) { scanf( for (int j=1;j<=m;++j) { en[i][j]=ss[j]-'0'; if (st[i][j]==1 && en[i][j]==st[i][j]) ++t2; } } for (int i=1;i<=n;++i) { scanf( for (int j=1;j<=m;++j) cnt[i][j]=ss[j]-'0'; } }
Comments NOTHING