HDU 5294 Tricks Device (最大流+最短路)

题目链接:HDU 5294 Tricks Device

题意:n个点,m条边,并且一个人从1走到n只会走1到n的最短路径,问至少破坏几条边使原图的最短路不存在,最多破坏几条边使原图的最短路劲仍存在

思路:

1.跑一遍最短路,记录下所有最短路径,将这些最短路径的边以(0,1)(流量,容量)加到网络流中,跑一遍最大流

2.记录下的所有最短路径,再加到新的最短路的图中,边权为1,跑一遍最短路,m-最短路 就是答案

注意:有重边的情况

比如:

2 3

1 2 1

1 2 1

1 2 1

ans: 3 2

AC代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <set>
using namespace std;
const int MAXN=2010;
const int MAXM=60010;
#define typec int
const typec INF=0x3f3f3f3f;//防止后面溢出,这个不能太大

struct Edge {
	int to,next,cap,flow;
} edge[MAXM*4]; //注意是MAXM
int tol;
int head[MAXN];
int gap[MAXN],dep[MAXN],cur[MAXN];
void add(int u,int v,int w,int rw = 0) {
	edge[tol].to = v;
	edge[tol].cap = w;
	edge[tol].flow = 0;
	edge[tol].next = head[u];
	head[u] = tol++;
	edge[tol].to = u;
	edge[tol].cap = rw;
	edge[tol].flow = 0;
	edge[tol].next = head[v];
	head[v] = tol++;
}
int Q[MAXN];
void BFS(int start,int end) {
	memset(dep,-1,sizeof(dep));
	memset(gap,0,sizeof(gap));
	gap[0] = 1;
	int front = 0, rear = 0;
	dep[end] = 0;
	Q[rear++] = end;
	while(front != rear) {
		int u = Q[front++];
		for(int i = head[u]; i != -1; i = edge[i].next) {
			int v = edge[i].to;
			if(dep[v] != -1)continue;
			Q[rear++] = v;
			dep[v] = dep[u] + 1;
			gap[dep[v]]++;
		}
	}
}
int S[MAXN];
int sap(int start,int end,int N) {
	BFS(start,end);
	memcpy(cur,head,sizeof(head));
	int top = 0;
	int u = start;
	int ans = 0;
	while(dep[start] < N) {
		if(u == end) {
			int Min = INF;
			int inser;
			for(int i = 0; i < top; i++)
				if(Min > edge[S[i]].cap - edge[S[i]].flow) {
					Min = edge[S[i]].cap - edge[S[i]].flow;
					inser = i;
				}
				for(int i = 0; i < top; i++) {
					edge[S[i]].flow += Min;
					edge[S[i]^1].flow -= Min;
				}
				ans += Min;
				top = inser;
				u = edge[S[top]^1].to;
				continue;
		}
		bool flag = false;
		int v;
		for(int i = cur[u]; i != -1; i = edge[i].next) {
			v = edge[i].to;
			if(edge[i].cap - edge[i].flow && dep[v]+1 == dep[u]) {
				flag = true;
				cur[u] = i;
				break;
			}
		}
		if(flag) {
			S[top++] = cur[u];
			u = v;
			continue;
		}
		int Min = N;
		for(int i = head[u]; i != -1; i = edge[i].next)
			if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) {
				Min = dep[edge[i].to];
				cur[u] = i;
			}
			gap[dep[u]]--;
			if(!gap[dep[u]])return ans;
			dep[u] = Min + 1;
			gap[dep[u]]++;
			if(u != start)u = edge[S[--top]^1].to;
	}
	return ans;
}
void init() {
	tol = 0;
	memset(head,-1,sizeof(head));
}

//-------------------------------------------------
struct Edge2 {
	int v;
	int cost;
	Edge2(int _v=0,int _cost=0):v(_v),cost(_cost){}
};
vector<Edge2>E[MAXN],E2[MAXN];
void addedge(int u,int v,int w) {
	E[u].push_back(Edge2(v,w));
}
bool vis[MAXN];//在队列标志
int cnt[MAXN];//每个点的入队列次数
int dist[MAXN];

bool SPFA(int start,int n) {
	memset(vis,false,sizeof(vis));
	for(int i=1;i<=n;i++)
		dist[i]=INF;
	vis[start]=true;
	dist[start]=0;
	queue<int>que;
	while(!que.empty())que.pop();
	que.push(start);
	memset(cnt,0,sizeof(cnt));
	cnt[start]=1;
	while(!que.empty())	{
		int u=que.front();
		que.pop();
		vis[u]=false;
		for(int i=0;i<E[u].size();i++){
			int v=E[u][i].v;
			if(dist[v]>dist[u]+E[u][i].cost){
				dist[v]=dist[u]+E[u][i].cost;
				if(!vis[v]){
					vis[v]=true;
					que.push(v);
					if(++cnt[v]>n) return false;
					//cnt[i]为入队列次数,用来判定是否存在负环回路
				}
			}
		}
	}
	return true;
}

set<int> s;
int main() {
	int i,j,m,n;
	int a,b,c;
	while(scanf("%d %d",&n,&m)!=EOF) {
		init();
		s.clear();
		for(i=1;i<=n;i++) E[i].clear();
		for(i=0; i<m; i++) {
			scanf("%d %d %d",&a,&b,&c);
			addedge(a,b,c);
			addedge(b,a,c);
		}
		int ok=SPFA(1,n);
		for(i=1;i<=n;i++){
			E2[i]=E[i];
			E[i].clear();
		}
		for(i=1; i<=n; i++) {
			int sz=E2[i].size();
			for(j=0; j<sz; j++) {
				int u=i;
				int v=E2[i][j].v;
				//得到最短路的边
				if(dist[u]+E2[i][j].cost==dist[v]) {
					add(u,v,1);
					s.insert(u),s.insert(v);
					addedge(u,v,1);
				}
			}
		}
		int ans=sap(1,n,(int)s.size());
		ok=SPFA(1,n);
		printf("%d %d\n",ans,m-dist[n]);
	}
	return 0;
}
/*
2 3
1 2 1
1 2 1
1 2 1
2 5
1 2 2
1 2 2
1 2 1
1 2 1
1 2 1
*/

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-27 03:32:25

HDU 5294 Tricks Device (最大流+最短路)的相关文章

hdu 5294 Tricks Device(最短路 + 最大流)

hdu 5294 Tricks Device 题目大意:吴邪在古墓中追张起灵,古墓中有很多条路,走每条路都需要一个时间,吴邪只有在最短的时间从古墓的入口到达出口才能追上张起灵.但是张起灵很厉害,他可以使用奇门遁甲使一条路无法通行.现在,问,张起灵最少堵住几条路就可以使吴邪追不上他,以及在吴邪可以追上张起灵的情况下,张起灵最多能堵多少条路. 解题思路:先求出古墓中的最短路(耗时最少的路),再求最短路的同时,记录走最短路要通过哪几条路和走最短路最少通过的路数.最多能堵住的路就是总的路数减去走最短路所

hdu 5294 Tricks Device 最短路建图+最小割

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5294 Tricks Device Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 375    Accepted Submission(s): 98 Problem Description Innocent Wu follows Dumb Zh

HDU 5294 Tricks Device(多校2015 最大流+最短路啊)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5294 Problem Description Innocent Wu follows Dumb Zhang into a ancient tomb. Innocent Wu's at the entrance of the tomb while Dumb Zhang's at the end of it. The tomb is made up of many chambers, the total

hdu 5294 Tricks Device(2015多校第一场第7题)最大流+最短路

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5294 题意:给你n个墓室,m条路径,一个人在1号墓室(起点),另一个人在n号墓室(终点),起点的那个人只有通过最短路径才能追上终点的那个人,而终点的那个人能切断任意路径. 第一问--终点那人要使起点那人不能追上的情况下可以切的最少的路径数,输出最少的路径数 第二问--起点那人能追上终点那人的情况下,终点那人能切断的最多的路径数,输出最多的路径数 思路:要使起点那人无法追上,只要使他的最短路径不存在就

hdu 5294 Tricks Device

求边最少最短路 求最短路构成的边权为1的图的最大流 两个 模板 #include <iostream> #include <stdio.h> #include <math.h> #include <string.h> #include <set> #include <map> #include <queue> #include <vector> #include <string> #include

HDU 5294(Tricks Device-最短路最小割)[Template:SPFA]

Tricks Device Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2389    Accepted Submission(s): 635 Problem Description Innocent Wu follows Dumb Zhang into a ancient tomb. Innocent Wu's at the en

HDOJ 5294 Tricks Device 最短路(记录路径)+最小割

最短路记录路径,同时求出最短的路径上最少要有多少条边, 然后用在最短路上的边重新构图后求最小割. Tricks Device Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 1584    Accepted Submission(s): 388 Problem Description Innocent Wu follows Dumb Z

HDU 5294 多校第一场1007题 最短路+最小割

Tricks Device Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1285    Accepted Submission(s): 302 Problem Description Innocent Wu follows Dumb Zhang into a ancient tomb. Innocent Wu’s at the ent

POJ 2135 Farm Tour &amp;&amp; HDU 2686 Matrix &amp;&amp; HDU 3376 Matrix Again 费用流求来回最短路

累了就要写题解,最近总是被虐到没脾气. 来回最短路问题貌似也可以用DP来搞,不过拿费用流还是很方便的. 可以转化成求满流为2 的最小花费.一般做法为拆点,对于 i 拆为2*i 和 2*i+1,然后连一条流量为1(花费根据题意来定) 的边来控制每个点只能通过一次. 额外添加source和sink来控制满流为2. 代码都雷同,以HDU3376为例. #include <algorithm> #include <iostream> #include <cstring> #in