【CodeVS 1227】 方格取数2

因为要用^来取反向边 所以每次加边加两条!来保证'^'的值是对的

题目规定取一次后变为0! 所以流量为0 这时 我们再加一条花费为0 的边来保证联通!!

#include <iostream>
#include <cstdio>
#include <cstring>
#define INF 100000000
using namespace std;
int id[51][51][2],cnt;
int n,k;
int g[500000+10],num[500000+10],nnext[500000+10],cost[500000+10],flow[500000+10],tot=2;
int s,t;
int fa[50000+10],fx[50000+10];
int team[50000*4],head,tail;
bool b[50000+10];
int d[50000+10];
void Add(int x,int y,int z,int f)
{
	num[tot]=y;
	nnext[tot]=g[x];
	g[x]=tot;
	cost[tot]=z;
	flow[tot]=f;
	tot++;
}
bool spfa()
{
	head=tail=0;
	memset(b,false,sizeof(b));
	for(int i=1;i<=cnt;i++) d[i]=-INF;
	d[s]=0;b[s]=true;team[++tail]=s;
	while(head<tail)
	{
		int x=team[++head];b[x]=false;
		for(int i=g[x];i;i=nnext[i])
		{
			int tmp=num[i];
			if(flow[i]!=0&&d[tmp]<d[x]+cost[i])
			{
				fa[tmp]=x;
				fx[tmp]=i;
				d[tmp]=d[x]+cost[i];
				if(!b[tmp]) team[++tail]=tmp,b[tmp]=true;
			}
		}
	}
	if(d[t]==-INF) return false;
	return true;
}
int main()
{

	scanf("%d %d",&n,&k);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
		{
			int tmp;
			scanf("%d",&tmp);
			id[i][j][0]=++cnt;
			id[i][j][1]=++cnt;
			if(i-1>=1)
				Add(id[i-1][j][1],id[i][j][0],0,INF),Add(id[i][j][0],id[i-1][j][1],0,0);
			if(j-1>=1)
				Add(id[i][j-1][1],id[i][j][0],0,INF),Add(id[i][j][0],id[i][j-1][1],0,0);
			Add(id[i][j][0],id[i][j][1],tmp,1),Add(id[i][j][1],id[i][j][0],-tmp,0);
			Add(id[i][j][0],id[i][j][1],0,INF),Add(id[i][j][1],id[i][j][0],0,0);
		}
	s=++cnt;t=++cnt;
	Add(s,id[1][1][0],0,k),Add(id[1][1][0],s,0,0);
	Add(id[n][n][1],t,0,k),Add(t,id[n][n][1],0,0);

	int ans=0;
	while(spfa())
	{
		int tmp=t;
		while(tmp!=s)
		{
			ans+=cost[fx[tmp]]; 
			flow[fx[tmp]]--;
			flow[fx[tmp]^1]++;
			tmp=fa[tmp];
		}
	}
	printf("%d\n",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/ofsxb/p/5105680.html