有任何问题欢迎留言或私聊
题目链接:BZOJ1797-点击做题
题目:
Description
A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路。设其中第i (1≤i≤M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci。现在B国想找出一个路径切断方案,使中转站s不能到达中转站t,并且切断路径的代价之和最小。 小可可一眼就看出,这是一个求最小割的问题。但爱思考的小可可并不局限于此。现在他对每条单向道路提出两个问题: 问题一:是否存在一个最小代价路径切断方案,其中该道路被切断? 问题二:是否对任何一个最小代价路径切断方案,都有该道路被切断? 现在请你回答这两个问题。
Input
第一行有4个正整数,依次为N,M,s和t。第2行到第(M+1)行每行3个正 整数v,u,c表示v中转站到u中转站之间有单向道路相连,单向道路的起点是v, 终点是u,切断它的代价是c(1≤c≤100000)。 注意:两个中转站之间可能有多条道路直接相连。 同一行相邻两数之间可能有一个或多个空格。
Output
对每条单向边,按输入顺序,依次输出一行,包含两个非0即1的整数,分 别表示对问题一和问题二的回答(其中输出1表示是,输出0表示否)。 同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。
题意和思路:
1。题目直接说了跑最大流,所以第一步就直接用板子跑最大流(最小割)就行了,我最大流的板子在这里
2。虽然你求出来了最小割答案,但是对于这个答案经过了多少条不同路径的还不清楚!不过我们知道每条边流量flow的变化量和它反向边流量flow的边化量。这点很重要。
3。知道了跑完最大流之后的流量,你就直接在这个残量网络上用tarjan缩点。
4。遍历每条边(不遍历反向边)。下面分情况讨论:
1.如果其反向边没有流量变化,代表最大流没有经过这条边,直接输出0 0;
2.如果这条边的两个端点缩点后在一个强连通分量中,就是说缩点后为同一点编号,那么也输出0 0;
3.如果两个端点缩点后,一个和S点在同一强连通分量另一个和T点在同一强连通分量,则输出1 1;反之输出1 0;
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<stack>
#define fuck(x) printf("*%d\n",x )
using namespace std;
typedef long long LL;
const int MAXN = 5005;
const int N = 5005;
const int X = 0x7fffffff;
const int INF = 0x3f3f3f3f ;
char s[MAXN];
struct lp{
int u,v, next;
LL cap;
} cw[MAXN * 100],temp[MAXN*100];
int n, m, vs, vt, NE, NV;
int head[MAXN],pre[MAXN],cur[MAXN],level[MAXN],gap[MAXN];
int vis[N],Index;
int dfn[N],low[N];
int qltNum;
int qltMap[N];
stack<int> st;
inline void Insert(int u, int v, LL cap)
{
cw[NE].v = v;
cw[NE].cap = cap;
cw[NE].next = head[u];
cw[NE].u=u;
head[u] = NE++;
cur[u] = head[u];
cw[NE].v = u;
cw[NE].u=v;
cw[NE].cap = 0;
cw[NE].next = head[v];
head[v] = NE++;
cur[v] = head[v];
}
LL SAP(int vs,int vt){
memset(level,0,sizeof(level));
memset(pre,-1,sizeof(pre));
memset(gap,0,sizeof(gap));
int u=pre[vs]=vs;
LL maxflow=0,aug=-1;
gap[0]=NV;
while(level[vs]<NV){
int flag=0;
for(int &i=cur[u];i!=-1;i=cw[i].next){
int v=cw[i].v;
if(cw[i].cap&&level[u]==level[v]+1){
aug==-1?(aug=cw[i].cap):(aug=min(aug,cw[i].cap));
pre[v]=u;
u=v;
if(v==vt){
maxflow+=aug;
for(u=pre[v];v!=vs;v=u,u=pre[u]){
cw[cur[u]].cap-=aug;
cw[cur[u]^1].cap+=aug;
}
aug=-1;
}
flag=1;
if(flag)break;
}
}
if(flag)continue;
int minlevel=NV;
for(int i=head[u];i!=-1;i=cw[i].next){
int v=cw[i].v;
if(cw[i].cap&&minlevel>level[v]){
cur[u]=i;
minlevel=level[v];
}
}
if((--gap[level[u]])==0)break;
level[u]=minlevel+1;
gap[level[u]]++;
u=pre[u];
}
return maxflow;
}
void dfs(int u,int fa){
dfn[u] = low[u] = ++Index;
vis[u]=1;int v;
st.push(u);
for(int i=head[u];~i;i=cw[i].next){
v=cw[i].v;
if(cw[i].cap<=0)continue;
if(!vis[v]){
dfs(v,u);
low[u]=min(low[u],low[v]);
}else if(vis[v]==1){
low[u]=min(low[u],dfn[v]);
}
}
if(low[u]==dfn[u]){
qltNum++;
do{
v=st.top();st.pop();
vis[v]=2;
qltMap[v]=qltNum;
}while(v!=u);
}
}
void tarjan(){
for(int i=1;i<=n;++i){
if(!vis[i]){
dfs(i,0);
}
}
}
void init(){
qltNum=0;while(!st.empty())st.pop();
Index=0;memset(vis,0,sizeof(vis));
memset(qltMap,0,sizeof(qltMap));
memset(low,0,sizeof(low));
memset(dfn,0,sizeof(dfn));
}
#define DEBUG
int main()
{
#ifdef DEBUG
freopen("D:in.in", "r", stdin);
freopen("D:out.out", "w", stdout);
#endif
int S,T;
while(~scanf("%d%d%d%d",&n,&m,&S,&T)) {
//n n
NV=n;NE=0;
vs=S,vt=T;
memset(head, -1, sizeof(head));
memset(cur, -1, sizeof(cur));
for(int i=0;i<m;++i){
int x,y;
LL z;
scanf("%d%d%lld",&x,&y,&z);
Insert(x,y,z);
}
LL ans =SAP(vs,vt);
init();
tarjan();
int qltS=qltMap[S],qltT=qltMap[T];
for(int i=0;i<NE;i+=2){
if(cw[i^1].cap>0){
if(qltMap[cw[i].u]!=qltMap[cw[i].v]){
if((qltMap[cw[i].u]==qltS&&qltMap[cw[i].v]==qltT)||(qltMap[cw[i].u]==qltT&&qltMap[cw[i].v]==qltS)){
printf("1 1\n");
}else printf("1 0\n");
}else{
printf("0 0\n");
}
}else printf("0 0\n");
}
}
return 0;
}
/*
1 0
1 0
0 0
1 0
0 0
1 0
1 0
最小割唯一性判定
jcvb:
在残余网络上跑tarjan求出所有SCC,记id[u]为点u所在SCC的编号。显然有id[s]!=id[t](否则s到t有通路,能继续增广)。
①对于任意一条满流边(u,v),(u,v)能够出现在某个最小割集中,当且仅当id[u]!=id[v];
②对于任意一条满流边(u,v),(u,v)必定出现在最小割集中,当且仅当id[u]==id[s]且id[v]==id[t]。
①
<==将每个SCC缩成一个点,得到的新图就只含有满流边了。那么新图的任一s-t割都对应原图的某个最小割,从中任取一个把id[u]和id[v]割开的割即可证明。
②
<==:假设将(u,v)的边权增大,那么残余网络中会出现s->u->v->t的通路,从而能继续增广,于是最大流流量(也就是最小割容量)会增大。这即说明(u,v)是最小割集中必须出现的边。
*/