链接:
#include <stdio.h>
int main()
{
puts("转载请注明出处[vmurder]谢谢");
puts("网址:blog.csdn.net/vmurder/article/details/44702813");
}
前言:
本来以为这种双限制流量的方法很通用很好用,所以没有去写那个一个点拆成俩的奇葩做法……但是后来我发现,这种一个点拆成三个的方法没有任何意义,它只是针对了这道题的特殊性质噗。好像并不能拓展。
题解:
首先图转化成源点往开始图的黑点(当然你要用白点也不是不行)流流量,最终从结束图的黑点流向汇点。这个应该都能想到。
然后关键是怎么在流过一次后同时限制两个点。
这也是我所想知道的……可是,下面的方法并没有告诉我该如何实现它,它用的是分析改流量。[请允许我做一个捂脸熊的表情]
我们分析:
如果一个点是初始图上的黑点,那么它可以
最多可以流入?限制修改次数2?,最多可以流出?限制修改次数+12?
如果一个点是目标图上的黑点,那么它可以
最多可以流入?限制修改次数+12?,最多可以流出?限制修改次数2?
否则
最多可以流入?限制修改次数2?,最多可以流出?限制修改次数2?
然后我们需要特判一下如果一个点既是初始图上的黑点,又是目标图上上的黑点,那么显然它的流入流出都应该跟【否则】那一部分一样。因为流入流出以后跟正常的点一样了么。
然后费用什么乱搞就行了,想设哪就设哪(但是乱设的话最终答案可能需要/2)
注意是八连通。
代码:
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 1300
#define M 10000
#define P 25
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3fll
using namespace std;
const int dx[]={-1,0,1,-1,1,-1,0,1};
const int dy[]={-1,-1,-1,0,0,1,1,1};
struct KSD
{
int u,v,len,fee,next;
}e[M];
int head[N],cnt;
inline void add(int u,int v,int len,int fee)
{
e[++cnt].u=u;
e[cnt].v=v;
e[cnt].len=len;
e[cnt].fee=fee;
e[cnt].next=head[u];
head[u]=cnt;
}
int dist[N],s,t;
int lim[N],pre[N];
bool in[N];
queue<int>q;
void spfa()
{
while(!q.empty())q.pop();
memset(dist,0x3f,sizeof dist);
q.push(s),dist[s]=0,lim[s]=inf;
int i,u,v;
while(!q.empty())
{
u=q.front(),q.pop(),in[u]=0;
for(i=head[u];i;i=e[i].next)if(e[i].len)
{
if(dist[v=e[i].v]>dist[u]+e[i].fee)
{
dist[v]=dist[u]+e[i].fee;
lim[v]=min(e[i].len,lim[u]);
pre[v]=i;
if(!in[v])q.push(v),in[v]=1;
}
}
}
return ;
}
void handle(int flow)
{
for(int i=pre[t];i;i=pre[e[i].u])
{
e[i].len-=flow;
e[i^1].len+=flow;
}
}
int minfee,maxflow,n,m,p;
char sta[P][P],end[P][P],str[P];
int id[P][P];
bool build()
{
int i,j,k;
int x,y;
scanf("%d%d",&n,&m);
s=0,t=n*m*3+1;
for(i=1;i<=n;i++)for(j=1;j<=m;j++)
id[i][j]=++cnt,cnt++,cnt++;
cnt=1;
for(i=1;i<=n;i++)
{
scanf("%s",sta[i]+1);
for(j=1;j<=m;j++)if(sta[i][j]==‘1‘)
{
p++;
add(s,id[i][j]+1,1,0);
add(id[i][j]+1,s,0,0);
}
}
maxflow=p;
for(i=1;i<=n;i++)
{
scanf("%s",end[i]+1);
for(j=1;j<=m;j++)if(end[i][j]==‘1‘)
{
p--;
add(id[i][j]+1,t,1,0);
add(t,id[i][j]+1,0,0);
}
}
if(p)return 1;
for(i=1;i<=n;i++)
{
scanf("%s",str+1);
for(j=1;j<=m;j++)
{
int flow=str[j]-‘0‘;
if(!flow)continue;
int flowa=(sta[i][j]==‘1‘)?(flow+1>>1):(flow>>1);
int flowb=(end[i][j]==‘1‘)?(flow+1>>1):(flow>>1);
if(sta[i][j]==‘1‘&&end[i][j]==‘1‘)flowa=flowb=flow>>1;
add(id[i][j],id[i][j]+1,flowb,1);
add(id[i][j]+1,id[i][j],0,-1);
add(id[i][j]+1,id[i][j]+2,flowa,1);
add(id[i][j]+2,id[i][j]+1,0,-1);
}
for(j=1;j<=m;j++)for(k=0;k<8;k++)
{
x=i+dx[k],y=j+dy[k];
if(id[x][y])
{
add(id[i][j]+2,id[x][y],inf,0);
add(id[x][y],id[i][j]+2,0,0);
}
}
}
return 0;
}
int main()
{
freopen("test.in","r",stdin);
if(build())
{
puts("-1");
return 0;
}
while(spfa(),dist[t]<inf)
{
minfee+=lim[t]*dist[t];
maxflow-=lim[t];
handle(lim[t]);
}
if(maxflow)puts("-1");
else cout<<(minfee>>1)<<endl;
return 0;
}
时间: 2024-10-27 13:35:38