最小截断[AHOI2009]

【题目描述】

宇宙旅行总是出现一些意想不到的问题,这次小可可所驾驶的宇宙飞船所停的空间站发生了故障,这个宇宙空间站非常大,它由N个子站组成,子站之间有M条单向通道,假设其中第i(1<=i<=M)条单向通道连接了xi,yi两个中转站,那么xi子站可以通过这个通道到达yi子站,如果截断这条通道,需要代价ci。现在为了将故障的代价控制到最小,小可可必须想出一个截断方案,使a站不能到达b子站,并且截断的代价之和最小。我们称之为最小截断,小可可很快解决了这个故障,但是爱思考的小可可并不局限于此,为了今后更方便的解决同类故障,他考虑对每条单向通道:

1,是否存在一个最小代价路径截断方案,其中该通道被切断?

2,是否对任何一个最小代价路径切断方案,都有该通道被切断?

聪明的你能帮小可可解决他的疑问吗?

【输入格式】

第一行有4个整数,依次为N,M,a和b;

第二行到第(m+1)行每行3个正整数x,y,c表示x子站到y子站之间有单向通道相连,单向通道的起点是x终点是y,切断它的代价是c(1<=c<=10000);

两个子站之间可能有多条通道直接连接。

【输出格式】

对每一个单向通道,按输入的顺序,依次输出一行包含两个非0即1的整数,分别表示对问题一和问题二的回答(其中1表示是,0表示否)。每行两个整数之间用一个空格分隔开。

【样例输入】

   6 7 1 6
   1 2 3
   1 3 2
   2 4 4
   2 5 1
   3 5 5
   4 6 2
   5 6 3

【样例输出】

1 0
1 0
0 0
1 0
0 0
1 0
1 0

【提示】

100%的数据中,N<=4000,M<=60000

70%的数据中,N<=1000,M<=40000

40%的数据中,N<=200,M<=2000

【题解】

     血帆海盗的进阶版,先贴结论XDDD:

最小割的必须边
       一定在最小割中的边、扩大容量后能增大最大流的边, ① 满流;② 残余网络中S能到入点、出点能到T。 从S开始DFS、T开始反向DFS,标记到达的点,然后枚举满流边即可。
       最小割的可行边
       被某一种最小割的方案包含的边, ① 满流;② 删掉之后在残余网络中找不到u到v的路径。 在残余网络中tarjan求SCC,(u,v)两点在同一SCC中说明残余网络中存在u到v路径。

在这道题里求必须边也可以用tarjan搞定,必须边的起点与S在同一个强联通分量里,终点与T在同一个强联通分量里。知道了结论之后就可以放心地跑了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
using namespace std;
const int sj=4010;
int n,m,s,t,e,a1,a2,a3;
int dep[sj],dfn[sj],c[sj],low[sj],h[sj];
stack<int> z;
queue<int> q;
bool r[sj];
struct B
{
    int ne,v,w,u;
}b[120010];
void add(int x,int y,int z)
{
     b[e].v=y;
     b[e].u=x;
     b[e].w=z;
     b[e].ne=h[x];
     h[x]=e++;
     b[e].v=x;
     b[e].w=0;
     b[e].u=y;
     b[e].ne=h[y];
     h[y]=e++;
}
bool bfs(int x)
{
     while(!q.empty()) q.pop();
     memset(dep,0,sizeof(dep));
     dep[x]=1;
     q.push(x);
     while(!q.empty())
     {
        x=q.front();
        q.pop();
        for(int i=h[x];i!=-1;i=b[i].ne)
          if(b[i].w&&!dep[b[i].v])
          {
             dep[b[i].v]=dep[x]+1;
             if(b[i].v==t) return 1;
             q.push(b[i].v);
          }
     }
     return 0;
}
int bj(int x,int y)
{
    return x<y?x:y;
}
int dfs(int x,int f)
{
    if(x==t)  return f;
    int ans=0,d;
    for(int i=h[x];i!=-1;i=b[i].ne)
      if(dep[b[i].v]>dep[x]&&b[i].w)
      {
         d=dfs(b[i].v,bj(b[i].w,f));
         f-=d;
         ans+=d;
         b[i].w-=d;
         b[i^1].w+=d;
         if(!f) break;
      }
    if(!ans) dep[x]=-1;
    return ans;
}
void tarjan(int x)
{
     low[x]=dfn[x]=++a1;
     z.push(x);
     r[x]=1;
     for(int i=h[x];i!=-1;i=b[i].ne)
     {
        if(!b[i].w) continue;
        if(!dfn[b[i].v])
        {
           tarjan(b[i].v);
           low[x]=bj(low[x],low[b[i].v]);
        }
        else if(r[b[i].v])
           low[x]=bj(low[x],dfn[b[i].v]);
     }
     if(low[x]==dfn[x])
     {
        a2++;
        do
        {
           a3=z.top();
           z.pop();
           c[a3]=a2;
           r[a3]=0;
        }while(a3!=x);
     }
}
void init()
{
     scanf("%d%d%d%d",&n,&m,&s,&t);
     memset(h,-1,sizeof(h));
     for(int i=1;i<=m;i++)
     {
       scanf("%d%d%d",&a1,&a2,&a3);
       add(a1,a2,a3);
     }
     while(bfs(s)) dfs(s,0x7fffffff);
     a1=a2=0;
     for(int i=1;i<=n;i++)
       if(!dfn[i]) tarjan(i);
     s=c[s];
     t=c[t];
}
void cl()
{
     for(int i=0;i<e;i+=2)
     {
        if(b[i].w) printf("0 0\n");
        if(!b[i].w)
        {
           if(c[b[i].u]!=c[b[i].v])
           {
              if(c[b[i].u]==s&&c[b[i].v]==t)
                printf("1 1\n");
              else printf("1 0\n");
           }
           else printf("0 0\n");
        }
     }
}
int main()
{
    init();
    cl();
    return 0;
}

mincut

时间: 2024-08-07 04:11:59

最小截断[AHOI2009]的相关文章

今天依然在切题的我

8:02 2017/6/14 Snowflake Snow Snowflakes 连数零都不会= =999983明明比100010大了将近9倍 17:15 2017/6/15 球形空间产生器sphere 本机RE的一些常见情况:大小不分,左右不分,正负不分,到底是i++还是i--:scanf万年不记得取地址. 15:12 2017/6/16 臭气弹 分不清ijk,分不清里外层循环,循环中变量用重.[后来看看这好像变成了NOIPDay1T2呢 高斯消元,找到主元之后如果它系数是0,这一位就不用消了

gensim中word2vec

from gensim.models import Word2Vec Word2Vec(self, sentences=None, size=100, alpha=0.025, window=5, min_count=5, max_vocab_size=None, sample=1e-3, seed=1, workers=3, min_alpha=0.0001, sg=0, hs=0, negative=5, cbow_mean=1, hashfxn=hash, iter=5, null_wor

AHOI2009最小割

1797: [Ahoi2009]Mincut 最小割 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1072  Solved: 446[Submit][Status] Description A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路.设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci.现在B国想找出一个路径切断方案,使中转站s不能到

BZOJ 1797: [Ahoi2009]Mincut 最小割( 网络流 )

先跑网络流, 然后在残余网络tarjan缩点. 考虑一条边(u,v): 当且仅当scc[u] != scc[v], (u,v)可能出现在最小割中...然而我并不会证明 当且仅当scc[u] = scc[S] && scc[v] == scc[T], (u, v) 必定出现在最小割中. 这个很好脑补, 假如这条边不是满流, 那么S-T就存在增广路了.. ----------------------------------------------------------------------

【BZOJ 1797】 [Ahoi2009]Mincut 最小割

1797: [Ahoi2009]Mincut 最小割 Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 1244  Solved: 512 [Submit][Status][Discuss] Description A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路.设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci.现在B国想找出一个路径切断

bzoj 1797: [Ahoi2009]Mincut 最小割

求最小割的可行边与必须边,先求一遍最大流,然后在残量网络上求强连通分量,对于可行边 起始点与结束点要在不同的强连通分量里,对于必须边 起始点要与S在一个SCC里 结束点要与T在一个SCC里. 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<queue> 7 #incl

[bzoj1797] [Ahoi2009]Mincut 最小割

问最小割中可能成为割边和一定会成为割边的边有哪些. 膜了半天各路题解. 比较详细的解释: http://blog.csdn.net/horizon_smz/article/details/50889806 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 const int maxn=4023,m

bzoj 1797: [Ahoi2009]Mincut 最小割【tarjan+最小割】

先跑一遍最大流,然后对残量网络(即所有没有满流的边)进行tarjan缩点. 能成为最小割的边一定满流:因为最小割不可能割一半的边: 连接s.t所在联通块的满流边一定在最小割里:如果不割掉这条边的话,就能再次从s到t增广 连接两个不同联通块的满流边可能在最小割里:新图(即缩点后只有满流边的图)的任意一条s.t割都是最小割,所以可以任取割的方案 #include<iostream> #include<cstdio> #include<cstring> #include<

[BZOJ1797][AHOI2009]最小割Mincut

bzoj luogu sol 一条边出现在最小割集中的必要条件和充分条件. 先跑出任意一个最小割,然后在残余网络上跑出\(scc\). 一条边\((u,v)\)在最小割集中的必要条件:\(bel[u]!=bel[v]\) 一条边\((u,v)\)在最小割集中的充分条件:\(bel[u]=bel[S],bel[v]=bel[T]\) code #include<cstdio> #include<algorithm> #include<cstring> #include&l