列表

详情


NC19887. [AHOI2009]MINCUT 最小割

描述

A,B两个国家正在交战,其中A国的物资运输网中有N个中转站,M条单向道路。设其中第i (1 ≤ i ≤ M)条道路连接了vi,ui两个中转站,那么中转站vi可以通过该道路到达ui中转站,如果切断这条道路,需要代价ci。现在B国想找出一个路径切断方案,使中转站s不能到达中转站t,并且切断路径的代价之和最小。 小可可一眼就看出,这是一个求最小割的问题。但爱思考的小可可并不局限于此。
现在他对每条单向道路提出两个问题: 
问题一:是否存在一个最小代价路径切断方案,其中该道路被切断? 
问题二:是否对任何一个最小代价路径切断方案,都有该道路被切断? 
现在请你回答这两个问题。

输入描述

第一行有4个正整数,依次为N,M,s和t。
第2行到第(M+1)行每行3个正整数v,u,c表示v中转站到u中转站之间有单向道路相连,单向道路的起点是v,终点是u,切断它的代价是c(1 ≤ c ≤ 100000)。
注意:两个中转站之间可能有多条道路直接相连。同一行相邻两数之间可能有一个或多个空格。

输出描述

对每条单向边,按输入顺序,依次输出一行,包含两个非0即1的整数,分别表示对问题一和问题二的回答(其中输出1表示是,输出0表示否)。
同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。

示例1

输入:

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

说明:

设第(i+1)行输入的边为i号边,那么{1,2},{6,7},{2,4,6}是仅有的三个最小代价切割方案。它们的并是{1,2,4,6,7},交是 {∅} 。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 44ms, 内存消耗: 3096K, 提交时间: 2020-08-19 19:27:25

#include<iostream>
#include<algorithm>
#include<stack>
#include<queue>
using namespace std;
const int inf = 2e9;
const int max_n = 4e3 + 100;
const int max_m = 1e6 + 100;
int n, m;int s, t;
int us[max_m], vs[max_m];

struct edge
{
	int to, cap, rev, next;
}E[max_m * 2];
int head[max_n];
int cnt = 1;
void add(int from, int to,int cap) {
	E[cnt].to = to;E[cnt].cap = cap;
	E[cnt].rev = cnt + 1;
	E[cnt].next = head[from];
	head[from] = cnt++;
	E[cnt].to = from;E[cnt].cap = 0;
	E[cnt].rev = cnt - 1;
	E[cnt].next = head[to];
	head[to] = cnt++;
}

int iter[max_n];
int dist[max_n];
bool searchpath(int s, int t) {
	fill(dist, dist + 1 + n, -1);
	queue<int> que;dist[s] = 0;
	que.push(s);
	while (!que.empty()) {
		int u = que.front();que.pop();
		for (int i = head[u];i;i = E[i].next) {
			edge& e = E[i];
			if (dist[e.to] != -1 || e.cap == 0)continue;
			dist[e.to] = dist[u] + 1;
			que.push(e.to);
		}
	}return dist[t] != -1;
}
int matchpath(int u, int t, int f) {
	if (u == t)return f;
	for (int& i = iter[u];i;i = E[i].next) {
		edge& e = E[i];
		if (dist[e.to] <= dist[u] || e.cap == 0)continue;
		int d = matchpath(e.to, t, min(f, e.cap));
		if (d <= 0)continue;
		e.cap -= d;E[e.rev].cap += d;
		return d;
	}return false;
}
int dinic(int s,int t) {
	int flow = 0;int f;
	while (searchpath(s, t)) {
		for (int i = 1;i <= n;i++)iter[i] = head[i];
		while (f = matchpath(s, t, inf))
			flow += f;
	}return flow;
}


int dfn[max_n], low[max_n], color[max_n];
int tot = 0, colour = 0;
stack<int> st;

void tarjan(int u) {
	dfn[u] = low[u] = tot++;st.push(u);
	for (int i = head[u];i;i = E[i].next) {
		edge& e = E[i];
		if (!e.cap)continue;
		if (!dfn[e.to]) { tarjan(e.to);low[u] = min(low[u], low[e.to]); }
		else if (color[e.to] == 0)low[u] = min(low[u], dfn[e.to]);
	}if (dfn[u] != low[u])return;
	colour++;
	while (st.top() != u) {
		color[st.top()] = colour;
		st.pop();
	}color[st.top()] = colour;st.pop();
}

int main() {
	ios::sync_with_stdio(0);
	cin >> n >> m >> s >> t;
	for (int i = 1;i <= m;i++) {
		int cap;
		cin >> us[i] >> vs[i] >> cap;
		add(us[i], vs[i], cap);
	}dinic(s, t);
	for (int i = 1;i <= n;i++)
		if (!dfn[i])tarjan(i);
	for (int i = 1;i <= m;i++) {
		edge& e = E[i * 2 - 1];
		if (e.cap || color[us[i]] == color[vs[i]])
			cout << "0 0\n";
		else if (color[us[i]] == color[s] && color[vs[i]] == color[t])
			cout << "1 1\n";
		else
			cout << "1 0\n";
	}
}

C++11(clang++ 3.9) 解法, 执行用时: 56ms, 内存消耗: 9548K, 提交时间: 2020-10-08 19:15:08

#include<bits/stdc++.h>
#define LL long long
#define pb push_back
using namespace std;
const int N=4e3+5,M=5e5+5,Inf=1e9;
struct Graph{int u,v;}g[M];
struct Edge{int to,f,nxt;}e[M<<1];
int n,m,s,t,fst[N],nf[N],tote,lev[N],q[N],hd,tl;
void adde(int u,int v,int w){
	e[++tote]=(Edge){v,w,fst[u]};fst[u]=tote;
	e[++tote]=(Edge){u,0,fst[v]};fst[v]=tote;
}
bool bfs(){
	for(int i=1;i<=n;i++)lev[i]=-1;
	q[hd=tl=1]=s;lev[s]=0;
	while(hd<=tl){
		int u=q[hd++];
		for(int i=fst[u],v;~i;i=e[i].nxt)if(e[i].f&&lev[v=e[i].to]<0)
			lev[v]=lev[u]+1,q[++tl]=v;
	}
	return lev[t]>=0;
}
int dfs(int u,int lim){
	if(u==t)return lim;
	int res=0;
	for(int i=nf[u],v,f;~i;i=e[i].nxt){
		v=e[i].to;f=e[i].f;
		if(lev[v]==lev[u]+1&&f){
			int tmp=dfs(v,min(lim,f));
			e[i].f-=tmp;e[i^1].f+=tmp;lim-=tmp;res+=tmp;
			if(!lim){nf[u]=i;return res;}
		}
	}
	nf[u]=-1;return res;
}
int dfn[N],low[N],id,st[N],tp,bel[N],tot;
vector<int>adj[N];
map<int,bool>lk[N];
void chkmi(int &x,int y){x=x<y?x:y;}
void addnew(int u,int v){adj[u].pb(v);lk[u][v]=true;}
void tarjan(int u){
	dfn[u]=low[u]=++id;st[++tp]=u;
	for(auto v:adj[u])if(!dfn[v])tarjan(v),chkmi(low[u],low[v]);else if(!bel[v])chkmi(low[u],dfn[v]);
	if(dfn[u]==low[u]){
		tot++;
		while(st[tp]!=u)bel[st[tp]]=tot,tp--;
		bel[st[tp]]=tot;tp--;
	}
}
int main(){
	memset(fst,-1,sizeof(fst));tote=1;
	scanf("%d%d%d%d",&n,&m,&s,&t);
	for(int i=1,u,v,w;i<=m;i++)scanf("%d%d%d",&u,&v,&w),adde(u,v,w),g[i]=(Graph){u,v};
	int flow=0;
	while(bfs())memcpy(nf,fst,sizeof(nf)),flow+=dfs(s,Inf);
	//printf("%d\n",flow);
	for(int u=1;u<=n;u++)for(int i=fst[u];~i;i=e[i].nxt)
		if(e[i].f)addnew(u,e[i].to);
	for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i);
	//for(int i=1;i<=n;i++)printf("%d%c",bel[i]," \n"[i==n]);
	for(int i=1,u,v;i<=m;i++){
		u=g[i].u;v=g[i].v;
		if(lk[u][v]||bel[u]==bel[v])puts("0 0");
		else{
			printf("1 ");
			if(bel[s]==bel[u]&&bel[v]==bel[t])puts("1");else puts("0");			
		}
	}
	return 0;
}

C++(g++ 7.5.0) 解法, 执行用时: 52ms, 内存消耗: 3216K, 提交时间: 2023-02-28 19:31:57

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+6;
using ll=long long;
int n,m,s,t;
int hd[N],ed[N],to[N];
struct Eg{int x,y;}g[N];
ll flow,w[N];
void run(){
    static int d[N],q[N],l,r,nw[N];
    function<bool()>bfs=[&](){
        int i,x,y;
        for(x=1;x<=n;++x)d[x]=0,nw[x]=hd[x];
        d[q[l=r=1]=t]=1;
        while(l<=r){
            x=q[l++];
            for(i=hd[x];i;i=to[i])
                w[i^1]&&!d[y=ed[i]]&&(d[q[++r]=y]=d[x]+1);
        }return d[s];
    };
    function<ll(int,ll)>dc=[&](int x,ll fl){
        if(x==t)return fl;
        int y;ll k,rs=fl;
        for(int &i=nw[x];i;i=to[i])
            if(w[i]&&d[y=ed[i]]==d[x]-1&&(k=dc(y,min(w[i],rs)))){
                w[i]-=k,w[i^1]+=k;if(!(rs-=k))return fl;
            }return fl-rs;
    };
    ll k;while(bfs())while(k=dc(s,1e18))flow+=k;
}
int dfn[N],inc[N],scc;
void tarjan(int x){
    static int low[N],dlt,stk[N],tp;
    int i,y;
    dfn[x]=low[x]=++dlt;
    stk[++tp]=x;
    for(i=hd[x];i;i=to[i])
        if(w[i]){
            if(dfn[y=ed[i]]){
                (!inc[y])&&low[x]>dfn[y]&&(low[x]=dfn[y]);
            }else{
                tarjan(y);
                low[x]>low[y]&&(low[x]=low[y]);
            }
        }
    if(dfn[x]==low[x]){
        ++scc;do{
            inc[stk[tp]]=scc;
        }while(stk[tp--]!=x);
    }
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m>>s>>t;
    int i,j,k,l,r,x,y;
    for(i=1;i<=m;++i){
        cin>>x>>y>>w[i+i],g[i]={x,y};
        to[i+i]=hd[ed[i+i+1]=x],hd[x]=i+i;
        to[i+i+1]=hd[ed[i+i]=y],hd[y]=i+i+1;
    }run();
    for(x=1;x<=n;++x)
        if(!dfn[x])tarjan(x);
    for(i=1;i<=m;++i)
        printf("%d %d\n",!w[i+i]&&inc[g[i].x]!=inc[g[i].y],
            !w[i+i]&&inc[g[i].x]==inc[s]&&inc[g[i].y]==inc[t]);
    return 0;
}

上一题