洛谷3163 CQOI2014危桥 (最大流)

一开始想了一发费用流做法然后直接出负环了

首先,比较显然的思路就是对于原图中没有限制的边,对应的流量就是\(inf\),如果是危桥,那么流量就应该是\(2\)

由于存在两个起始点,我们考虑直接\(s->a_1,s->b_1\)
然后对于终点,\(a_2->t,b_2->t\)

流量分别是次数的两倍!
(因为往返相当于跑双倍的单程)

然后跑最大流,看一下流量是不是\((2\times (a_n+b_n))\)

但是这样会存在一个瑕疵。就是跑出来的路径是\(a_1->b_2\)

那么这时候,我们选择交换\(b_1和b_2\)的位置,然后重新建图跑最大流。
如果流量还是那个值,那就是\(yes\)

这是为什么呢?如果两次都是等于\(2\times (a_n+b_n)\),那么只存在两种情况,要么是\(a_1->a_2\)是可行的,要么就是存在\(b1->a1->b2\)这样一条路径且路径的流量是\(2*b_n\),另一边同理。

所以当两次的流量都是合法的时候,那么一定就是\(Yes\),否则就是\(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;
}

转载于:https://www.cnblogs.com/yimmortal/p/10154699.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值