HDU3376(最小费用最大流)

解题思路:用拆点的方法,同一个点拆成两个,容量为1.这样保证每个点只能流过一次。写费用流时超时,后来把queue的初始化写到函数外了,省的每次调用函数都要初始化,然后就不超时,过了。

#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
int map[602][602];
struct node
{
	int u,v,c,w,next,id;
}s[4420000];
int head[600*600*2+5],cnt,dis[600*600*2+5],vis[600*600*2+5],pre[600*600*2+5];
const int inf=0x3f3f3f3f;
int en,st,n;
queue<int> q;
void add(int u,int v,int c,int w)
{
	s[cnt].u=u;
	s[cnt].v=v;
	s[cnt].c=c;
	s[cnt].w=w;
	s[cnt].id=cnt;
	s[cnt].next=head[u];
	head[u]=cnt++;
	
	s[cnt].u=v;
	s[cnt].v=u;
	s[cnt].c=0;
	s[cnt].w=-w;
	s[cnt].id=cnt;
	s[cnt].next=head[v];
	head[v]=cnt++;
}
bool spfa()
{
	fill(dis,dis+n*n*2,inf);
	fill(vis,vis+n*n*2,0);
	dis[0]=0;
	while(!q.empty()) q.pop();
	q.push(0);
	while(!q.empty())
	{
		int t=q.front();
		q.pop();
		vis[t]=0;
		for(int i=head[t];i!=-1;i=s[i].next)
		{
			int v=s[i].v;
			if(s[i].c>0&&dis[v]>dis[t]+s[i].w)
			{
				dis[v]=dis[t]+s[i].w;
				pre[v]=s[i].id;
				if(!vis[v])
				{
					vis[v]=1;
					q.push(v);
				}
			}
		}
	}
	if(dis[en]==inf)
	return false;
	//printf("*%d\n",dis[en]);
	return true;
}
void solve()
{
	int sum=0;
	while(spfa())
	{
		int min_flow=inf;
		for(int i=en;i!=st;i=s[pre[i]].u)
		{
			s[pre[i]].c-=1;
			s[pre[i]^1].c+=1;
		}
		sum+=dis[en];
	}
	printf("%d\n",-sum-map[0][0]-map[n-1][n-1]);
}
int main()
{
	//freopen("t.txt","r",stdin);
	while(scanf("%d",&n)!=EOF)
	{
		cnt=0;
		memset(head,-1,sizeof(head));
		int tp=n*n;
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<n;j++)
			{
				scanf("%d",&map[i][j]);
				if((i==0&&j==0)||(i==n-1&&j==n-1))
					add(i*n+j,i*n+j+tp,2,-map[i][j]);
				else
					add(i*n+j,i*n+j+tp,1,-map[i][j]);	
				
				if(i+1<n)
				{
					add(i*n+j+tp,(i+1)*n+j,1,0);
				}
				if(j+1<n)
				{
					add(i*n+j+tp,i*n+j+1,1,0);
				}
			}
		}
		en=(n-1)*n+n-1+tp;
		st=0;
		solve();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39861441/article/details/87632447