2019年杭电多校第一场 Path HDU - 6582 (SPFA+最小割)

本文介绍了一种结合最短路径与最大流算法解决特定图论问题的方法。通过求解所有最短路径并利用这些路径构建新图,进而使用最大流算法(最小割)来确定使路径增长所需的最小成本。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:https://cn.vjudge.net/problem/HDU-6582.

题意,给你一个有向图,一个人要从1到n走一条最短的路,可是Tom想让他走的更长一点,所以需要阻断一些路

问  用最少的cost使得这个人走的更长,输出这个cost

思路:就是找到所有的最短路,然后用这个最短路建图,从1到n跑最大流(即最小割)输出结果即可

注意:数据需要long long

这题和HDU-5889 Barricade思路一样

#include <algorithm>
#include <vector>
#include <cstdio>
#include <queue>
#include <cstring>
#define ll long long
using namespace std;
const ll INF = 1e17;
const int MAXN = 40005;
int N,M;
int u,v;
ll w;
struct Edge{
	int to ,rev;
	ll value;
	Edge() {}
	Edge(int a,ll b,int c):to(a),value(b),rev(c) {}
};
struct node1{
    int v,next;
	ll w;
}edge[MAXN];
vector<Edge> E[MAXN];
int deep[MAXN];
int iter[MAXN],head[MAXN];
int id;
void add(int u,int v,ll w){
    edge[id].v=v;
    edge[id].w=w;
    edge[id].next=head[u];
    head[u]=id++;
}
inline void Add(int from,int to,ll value){
	E[from].push_back(Edge(to,value,E[to].size()));
	E[to].push_back(Edge(from,0,E[from].size()-1));
}
 
bool BFS(int root,int target) {
	memset(deep,-1,sizeof deep);
	queue<int> Q;
	deep[root] = 0;
	Q.push(root);
	while(!Q.empty())
	{
		int t = Q.front();
		Q.pop();
		for(int i=0 ; i<E[t].size() ; i++)
		{
			if(E[t][i].value > 0 && deep[E[t][i].to] == -1)
			{
				deep[E[t][i].to] = deep[t] + 1;
				Q.push(E[t][i].to);
			}
		}
	}
	return deep[target] != -1;
}
 
ll DFS(int root,int target,ll flow){
	if(root == target) return flow;
	for(int &i=iter[root] ; i<E[root].size() ; i++)
	{
		if(E[root][i].value>0 && deep[E[root][i].to] == deep[root]+1)
		{
			ll nowflow = DFS(E[root][i].to,target,min(flow,E[root][i].value));
			if(nowflow > 0)
			{
				E[root][i].value -= nowflow;
				E[E[root][i].to][E[root][i].rev].value += nowflow;
				return nowflow;
			}
		}
	}
	return 0;
} 
bool vis[MAXN];
ll dist[MAXN];
void spfa(int s){
    memset(vis,0,sizeof(vis));
    for(int i=0;i<=N+10;i++)dist[i]=INF;
    vis[s]=1;
    dist[s]=0;
    queue<int>q;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        vis[u]=0; 
        for(int i=head[u]; i!=-1; i=edge[i].next){
            int v=edge[i].v;
            if (dist[v]>dist[u]+edge[i].w){
                dist[v]=dist[u]+edge[i].w;
                if (!vis[v]){
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
}
int Dinic(int root,int target){
	ll sumflow = 0;
	while(BFS(root,target))	{
		memset(iter,0,sizeof iter);
		ll mid;
		while(mid=DFS(root,target,INF))sumflow += mid;
	}
	return sumflow;
}
void init(){
	memset(head,-1,sizeof(head));
	id=0;
}
int main(){
 	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%d %d",&N,&M);
		init();
		for(int i=0 ; i< M ; i++){
			scanf("%d %d %lld",&u,&v,&w);
			add(u, v,w); 
		}
		spfa(1);
		for(int i = 1; i <= N; ++i) {
        	for(int j = head[i]; ~j; j = edge[j].next) {
          	  	int v = edge[j].v;
        		if(dist[v] - dist[i] == edge[j].w) {
           	     	Add(i, v, edge[j].w);
           	 	}
        	}
    	}
		printf("%lld\n",Dinic(1,N));
		for (int i = 0; i <= 12000;i++) E[i].clear();
	}
	return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值