hdu6582

path

题意:\(n\)个点\(m\)条边的有向图,需要砍掉几条边使从\(1\)\(n\)的最短路变长,问花费的最小值。花费等于砍掉的所有边的权值和。

题解:两遍dij跑出所有属于\(1\)\(n\)的最短路的边(边需要满足的条件为\(dis1[u]+w+dis2[v]==dis1[n]\),\(dis1\)以1为源点,\(dis2\)以n为源点).用这些边建图,对这个图跑最小割即可. 一道板题敲半天TUT

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,int> pa;
const int maxn=20005;
int n,m;
const ll inf=0x3f3f3f3f;
struct node{
	int v,nxt;
	ll w;
}edge[maxn],edge2[maxn];
int head[maxn],cnt=0,head2[maxn],cnt2=0;
void add(int u,int v,ll w){
	edge[cnt].v=v;
	edge[cnt].w=w;
	edge[cnt].nxt=head[u];
	head[u]=cnt++;
}
void add2(int u,int v,ll w){
	edge2[cnt2].v=v;
	edge2[cnt2].w=w;
	edge2[cnt2].nxt=head2[u];
	head2[u]=cnt2++;
}
ll dis[maxn];
bool bfs(){
	if(n==1) return 0;
	for(int i=1;i<=n;i++) dis[i]=-1;
	queue<int> que;
	que.push(1);
	dis[1]=1;
	while(!que.empty()){
		int u=que.front();
		que.pop();
		for(int i=head2[u];~i;i=edge2[i].nxt){
			int v=edge2[i].v;
			if(edge2[i].w&&dis[v]<0){
				//cout << u << " " << v << " " << edge2[i].w << '\n';
				dis[v]=dis[u]+1;
				que.push(v);
			}
		}
	}
	return dis[n]!=-1;
}
ll dinic(int now,ll w){
	if(now==n) {
		if(w==inf) return 0;
		return w;
	}
	ll res=0;
	for(int i=head2[now];~i;i=edge2[i].nxt){
		int v=edge2[i].v;
		if(edge2[i].w&&dis[v]==dis[now]+1){
			ll tmp=dinic(v,min(edge2[i].w,w));
			edge2[i].w-=tmp;
			edge2[i^1].w+=tmp;
			res += tmp;
			if(res==w) return w;
		}
	}
	return res;
}

void dij(int s){
	bool vis[maxn];
	memset(vis,0,sizeof(vis));
	memset(dis,inf,sizeof(dis));
	priority_queue<pa,vector<pa>,greater<pa> > que;
	que.push(make_pair(0,s));
	dis[s]=0;
	while(!que.empty()){
		int u=que.top().second;
		que.pop();
		if(vis[u]) continue;
		vis[u]=true;
		for(int i=head[u];~i;i=edge[i].nxt){
			int v=edge[i].v;
			ll w=edge[i].w;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				que.push(make_pair(dis[v],v));
			}
		}
	}
}
int input[maxn][3];
ll dis1[maxn],dis2[maxn];
int main(){
	int T;
	cin >> T;
	while(T--){
		scanf("%d%d",&n,&m);
		for(int i=1;i<=m;i++){
			scanf("%d%d%d",&input[i][0],&input[i][1],&input[i][2]);
		}
		for(int i=1;i<=n;i++) head[i]=-1;
		cnt=0;
		for(int i=1;i<=m;i++) add(input[i][1],input[i][0],input[i][2]);
		dij(n);
		memcpy(dis2,dis,sizeof(dis));
		for(int i=1;i<=n;i++) head[i]=-1;
		cnt=0;
		for(int i=1;i<=m;i++){
			add(input[i][0],input[i][1],input[i][2]);
		}
		dij(1);
		memcpy(dis1,dis,sizeof(dis));
		cnt2=0;
		for(int i=1;i<=n;i++) head2[i]=-1;
		for(int u=1;u<=n;u++){
			for(int i=head[u];~i;i=edge[i].nxt){
				int v=edge[i].v;
				ll w=edge[i].w;
				if(dis1[u]+w+dis2[v]==dis1[n]){
					add2(u,v,w);
					add2(v,u,0);
				}
			}
		}
		ll ans=0;
		while(bfs()){
			//cout << dis[n]<<'\n';
			ans += dinic(1,inf);
		}
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2019-09-10 13:49  rain_star  阅读(95)  评论(0编辑  收藏  举报