zoj 3792 Romantic Value(最小割下边数最小)

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5300

大致题意:给出一个无向图,以及起点与终点。要删除一些边使得起点与终点不连通,在删掉边的权值之和最小的情况下要求删除的边数尽量少。求出一个比值:剩余边数权值和/删除的边数。

思路:删除边的权值之和最小显然是求最小割即最大流。但同时要求删除边数最少,解决方法是把边数也加到权值上去,一起求最大流,因为边数最多是1000,即每条边的边权置为 w*10000+1,1代表这一条边。然后求最小割,同时也把最小边数求了出来。若求得的最小割是ans,那么删除的边数为ans%10000,最小割是ans/10000。

#include <stdio.h>
#include <iostream>
#include <map>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
#define LL long long
#define _LL __int64
#define eps 1e-8
#define PI acos(-1.0)
using namespace std;

const int INF = 0x3f3f3f3f;
const int maxn = 55;
const int maxm = 1010;

struct node
{
	int v,w,next,re;
}edge[4*maxm];

int n,m,s,t;
int cnt,head[maxn];
int dis[maxn],vis[maxn];
queue <int> que;

void init()
{
	cnt = 0;
	memset(head,-1,sizeof(head));
}

void add(int u, int v, int w)
{
	edge[cnt] = ((struct node){v,w,head[u],cnt+1});
	head[u] = cnt++;

	edge[cnt] = ((struct node){u,0,head[v],cnt-1});
	head[v] = cnt++;
}

bool bfs()
{
	memset(vis,0,sizeof(vis));
	memset(dis,0,sizeof(dis));
	while(!que.empty()) que.pop();

	dis[s] = 0;
	vis[s] = 1;
	que.push(s);

	while(!que.empty())
	{
		int u = que.front();
		que.pop();
		for(int i = head[u]; i != -1; i = edge[i].next)
		{
			int v = edge[i].v;
			if(!vis[v] && edge[i].w)
			{
				vis[v] = 1;
				que.push(v);
				dis[v] = dis[u] + 1;
			}
		}
	}
	if(dis[t] == 0)
		return false;
	return true;
}

int dfs(int u, int delta)
{
	if(u == t)
		return delta;
	int ret = 0,tmp;

	for(int i = head[u]; i != -1; i = edge[i].next)
	{
		int v = edge[i].v;
		if(edge[i].w && dis[v] == dis[u] + 1 && (tmp = dfs(v,min(delta,edge[i].w))))
		{
			edge[i].w -= tmp;
			edge[edge[i].re].w += tmp;
			return tmp;
		}
	}
	if(!ret)
		dis[u] = -1;
	return ret;
}

int Dinic()
{
	int ans = 0,res;
	while(bfs())
	{
		while(res = dfs(s,INF))
			ans += res;
	}
	return ans;
}

int main()
{
	int test;
	int u,v,w;
	int sum;

	scanf("%d",&test);
	while(test--)
	{
		scanf("%d %d %d %d",&n,&m,&s,&t);
		init();
		sum = 0;
		for(int i = 1; i <= m; i++)
		{
			scanf("%d %d %d",&u,&v,&w);
			add(u,v,w*10000+1);
			add(v,u,w*10000+1);
			sum += w;
		}

		int ans = Dinic();
		if(ans == 0)
		{
			printf("Inf\n");
			continue;
		}

		int a = sum - ans/10000;
		int b = ans%10000;
		printf("%.2lf\n",(double)a/b);
	}
	return 0;
}

zoj 3792 Romantic Value(最小割下边数最小)

时间: 2024-10-05 05:11:43

zoj 3792 Romantic Value(最小割下边数最小)的相关文章

hdu 3987 求最小割条数最小

题意:    一个人要从起点  0  到达 n-1   n个点  m条路  ,我们求最少破坏路的条数使无法 从起点到达终点.题意很明显  ,求最小割条数最少,由于最小割流量虽然固定,但是其条数却不固定,可以破坏3条路,也可以破坏4条路,他们总流量相同才会出现这种情况. 题解:由于上述的情况,他们总流量相同但是条数不同,现在我们需要改变边的容量使得条数少边才是最小割,条数多的将不会是最小割. 官方题解有两种 ,我选择的是在残余网络中进行扩充流的操作,使的两个最小割不同,残余网络中,我进行所有边流量

ZOJ 3792 Romantic Value(ISAP &amp;&amp; 最小割)

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3792 这题是求最小割,但是不会求最小割,龙哥教的权值先*10000+1,利用前向星加边,来储存地图,得到的最大流量/10000,对%10000就是割边   Result Accepted ID  3792 Language  C++ Time  0ms 352KB #include <iostream> #include <cstdlib> #in

ZOJ 3792 Romantic Value(网络流之最小割)(找割边)

题目地址:ZOJ 3792 最小割做的太少..这题很明显是找割边.找割边就是判断正向弧是否是0.如果跑完一次最小割后正向弧流量为0的话,那就说明这个边为一条割边.但是找到了割边后再怎么办呢..中午睡觉的时候突然来了灵感..再利用这些割边求一次最大流不就行了..把割边的流量都设为1,其他的都为正无穷.那最后的流量就是最少需要的割边了.然后计算就可以了. 这次又把上限值直接设为sink+1了...导致WA了12发.....sad...以后得注意... 代码如下: #include <iostream

ZOJ 3792 Romantic Value 最小割(最小费用下最小边数)

求最小割及最小花费 把边权c = c*10000+1 然后跑一个最小割,则flow / 10000就是费用 flow%10000就是边数. 且是边数最少的情况.. #include<stdio.h> #include<string.h> #include<iostream> #include<math.h> #include<algorithm> #include<queue> #include<vector> using

ZOJ 3792 Romantic Value 最小割+求割边的数量

点击打开链接 Romantic Value Time Limit: 2 Seconds      Memory Limit: 65536 KB Farmer John is a diligent man. He spent a lot of time building roads between his farms. From his point of view, every road is romantic because the scenery along it is very harmon

zoj 3792 Romantic Value

题目链接 求最小割的值, 以及割边最少的情况的边数. 先求一遍最小割, 然后把所有割边的权值变为1, 其他边变成inf, 在求一遍最小割, 此时求出的就是最少边数. Inf打成inf  WA了好几发............ 1 #include<bits/stdc++.h> 2 using namespace std; 3 #define pb(x) push_back(x) 4 #define ll long long 5 #define mk(x, y) make_pair(x, y) 6

bzoj 1797: [Ahoi2009]Mincut 最小割【tarjan+最小割】

先跑一遍最大流,然后对残量网络(即所有没有满流的边)进行tarjan缩点. 能成为最小割的边一定满流:因为最小割不可能割一半的边: 连接s.t所在联通块的满流边一定在最小割里:如果不割掉这条边的话,就能再次从s到t增广 连接两个不同联通块的满流边可能在最小割里:新图(即缩点后只有满流边的图)的任意一条s.t割都是最小割,所以可以任取割的方案 #include<iostream> #include<cstdio> #include<cstring> #include<

二分图/网络流/最小割/最大流/最小费用最大流等等 模板

二分图匹配: 1.匈牙利算法  O(n * m)  n为二分图左侧点数  m为二分图右侧点数 #include<bits/stdc++.h> using namespace std; const int N=1e7; struct node{ int from,to,nxt; }e[N]; int head[N],cnt; int n; int v[N],ans,A,B,d[N]; void add(int from,int to){ e[++cnt].nxt=head[from]; e[cn

zoj 2874 &amp; poj 3308 Paratroopers (最小割)

题意: 一个m*n大小的网格,已知伞兵着陆的具体位置(行和列).现在在某行(或某列) 安装一架激光枪,一架激光枪能杀死该行(或该列)所有的伞兵.在第i行安装一架 激光枪的费用是Ri,在第i列安装的费用是Ci.要安装整个激光枪系统,总费用为这些 激光枪费用的乘积. 求杀死所有伞兵的最小费用. 构图: 把伞兵视为边,行与列视为顶点.增加源点和汇点,对于第i行,从源点向顶点i连接一条 容量为Ri的边.对于第j列,从顶点j向汇点连接一条容量为Rj的边. 如果某一点(i,j)有伞兵降落,则从顶点Ri向顶点