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