1. 程式人生 > >洛谷3163 CQOI2014危橋 (最大流)

洛谷3163 CQOI2014危橋 (最大流)

一開始想了一發費用流做法然後直接出負環了

首先,比較顯然的思路就是對於原圖中沒有限制的邊,對應的流量就是 i n f inf ,如果是危橋,那麼流量就應該是 2

2

由於存在兩個起始點,我們考慮直接 s > a 1 , s

> b 1 s->a_1,s->b_1
然後對於終點, a
2 > t , b 2 > t a_2->t,b_2->t

流量分別是次數的兩倍!
(因為往返相當於跑雙倍的單程)

然後跑最大流,看一下流量是不是 ( 2 × ( a n + b n ) ) (2\times (a_n+b_n))

但是這樣會存在一個瑕疵。就是跑出來的路徑是 a 1 > b 2 a_1->b_2

那麼這時候,我們選擇交換 b 1 b 2 b_1和b_2 的位置,然後重新建圖跑最大流。
如果流量還是那個值,那就是 y e s yes

這是為什麼呢?如果兩次都是等於 2 × ( a n + b n ) 2\times (a_n+b_n) ,那麼只存在兩種情況,要麼是 a 1 > a 2 a_1->a_2 是可行的,要麼就是存在 b 1 > a 1 > b 2 b1->a1->b2 這樣一條路徑且路徑的流量是 2 b n 2*b_n ,另一邊同理。

所以當兩次的流量都是合法的時候,那麼一定就是 Y e s Yes ,否則就是 N o No

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk make_pair
#define ll long long
using namespace std;
inline int read()
{
  int x=0,f=1;char ch=getchar();
  while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
  while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}
const int maxn = 3010;
const int maxm = 2e6+1e2;
const int inf = 1e9;
int point[maxn],nxt[maxm],to[maxm];
int flow[maxm],val[maxm];
int cnt=1,n,m;
int pre[maxm],from[maxn];
int dis[maxn],vis[maxn];
int num;
int s,t;
void addedge(int x,int y,int w)
{
	nxt[++cnt]=point[x];
	to[cnt]=y;
	point[x]=cnt;
	val[cnt]=w;
}
void insert(int x,int y,int w)
{
  addedge(x,y,w);
  addedge(y,x,0);
}
int h[maxn];
queue<int> q;
bool bfs(int s)
{
	  memset(h,-1,sizeof(h));
	  h[s]=0;
	  q.push(s);
	  while (!q.empty())
	  {
	  	int x=q.front();
	  	q.pop();
	  	for (int i=point[x];i;i=nxt[i])
	  	{
	  		int p  = to[i];
	  		if (h[p]==-1 && val[i]>0)
	  		{
	  			q.push(p);
	  			h[p]=h[x]+1;
			  }
		  }
	  }
	  if (h[t]==-1) return false;
	  return true;
}
int dfs(int x,int low)
{
	if (x==t || low==0) return low;
	int totflow=0;
	for (int i=point[x];i;i=nxt[i])
	{
		int p = to[i];
		if (h[p]==h[x]+1 && val[i]>0)
		{
			int tmp = dfs(p,min(low,val[i]));
			val[i]-=tmp;
			val[i^1]+=tmp;
			totflow+=tmp;
			low-=tmp;
			if(low==0) return totflow;
		}
	}
	if(low>0) h[x]=-1;
	return totflow;
}
int dinic()
{
	int ans=0;
	while (bfs(s))
	{
		ans=ans+dfs(s,inf); 
	}
	return ans;
}
int a,b,c,d,e,f;
char ss[1010][1010];
void init()
{
	cnt=1;
	memset(point,0,sizeof(point));
	memset(from,0,sizeof(from));
}
int main()
{
  while(scanf("%d%d%d%d%d%d%d",&n,&a,&b,&c,&d,&e,&f)!=EOF)
  {
  	init();
    a++;
    b++;
    e++;
    d++; 
  	for (int i=1;i<=n;i++)
  	{
  	 
  	 	scanf("%s",ss[i]+1);
  	 	for (int j=1;j<=n;j++)
  		 {
  	 		if (ss[i][j]=='X') continue;
  	 		if (ss[i][j]=='O') insert(i,j,2);
  	 		if (ss[i][j]=='N') insert(i,j,inf);
	 	}	
  	}
  	int tag=0;
  	s=maxn-10;
 	 t=s+1;
	  insert(s,a,2*c);
	  insert(b,t,2*c);
	  insert(s,d,2*f);
	  insert(e,t,2*f);
	  if (dinic()==2*(c+f)) tag++;
	  init();
	  for (int i=1;i<=n;i++)
  	  {
  	 	for (int j=1;j<=n;j++)
  		 {
  	 		if (ss[i][j]=='X') continue;
  	 		if (ss[i][j]=='O') insert(i,j,2);
  	 		if (ss[i][j]=='N') insert(i,j,inf);
	 	}	
    	}
      insert(s,a,2*c);
	  insert(b,t,2*c);
	  insert(s,e,2*f);
	  insert(d,t,2*f);
	  if (dinic()==2*(c+f)) tag++;
	  if(tag==2)
	  {
	  	cout<<"Yes\n";
	  }
	  else
	  {
	  	 cout<<"No\n";
	  }
  }
  return 0;
}