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

题意:给你n个点,m条边(有单向边也有双向边),由于最小割不止一种,求所有最小割种,边数最少的那个割集,输出最少的边数

两个思路:

1、先跑一遍最大流,然后让饱和的边的容量置为1,不饱和的置为INF,再跑一遍最大流即可

2、让每条边的边权乘上一个大于边数的数再加1,然后跑一边最大流,最后输出结果%乘的那个数即可

#include <algorithm>
#include <vector>
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX = (1ll << 31) - 1;
const int mavn = 4e5+5;
const int maxn = 1e5+5;
#define ll long long
struct Edge{
    int to;
    ll dis;
    int rev;
    Edge(){}
    Edge(int to,ll d,int c):to(to),dis(d),rev(c){}
};
vector<Edge> v[maxn];
int cur[mavn];
int n, m, s, t;
struct node {
	int u,v,d;
	ll c;
	node(){}
	node(int a,int b,ll c,int d):u(a),v(b),c(c),d(d){}
}pos[mavn];
void addEdge(int from, int to, ll dis){
    v[from].push_back(Edge(to, dis,v[to].size()));
    v[to].push_back(Edge(from, 0,v[from].size()-1));
}
int d[mavn],cnt;
ll DFS(int u, ll flow){
    if (u == t || !flow) return flow;
    ll ans = 0, tmp_flow;
    for (int& i = cur[u]; i < v[u].size(); i++){
        int to = v[u][i].to;
        if (d[to] == d[u] + 1 && v[u][i].dis > 0){
            tmp_flow = DFS(to, min(flow, v[u][i].dis));
            if(tmp_flow > 0) {
        	flow -= tmp_flow;
		v[u][i].dis -= tmp_flow;
		ans += tmp_flow;
		v[to][v[u][i].rev].dis += tmp_flow;
		if (!flow)
	            break;
            }
        }
    }
    if (!ans) d[u] = -1;
    return ans;
}
bool BFS(){
    memset(d,-1,sizeof(d));
    queue<int> que;
    que.push(s);
    d[s] = 0;
    int u, _new;
    while (!que.empty()){
        u = que.front();
        que.pop();
        for (int i = 0; i < v[u].size(); i++){
            _new = v[u][i].to;
            if (d[_new] == -1 && v[u][i].dis > 0){
                d[_new] = d[u] + 1;
                que.push(_new);
            }
        }
    }
    return (d[t] != -1);
}
ll  dinic(){
    ll max_flow = 0;
    cnt=0;
    while (BFS()){
        memset(cur,0,sizeof(cur));
        ll t;
        while((t = DFS(s,MAX)) > 0) max_flow += t;
    }
	return max_flow;
}

int T,case=1;

int main(){
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) {
            int x,y,a;	ll c;
            scanf("%d%d%lld%d",&x,&y,&c,&a);
            addEdge(x,y,c*(m+1) + 1);
            if(a) addEdge(y,x,c*(m+1)+1);
        }
        s = 0, t = n - 1;
        ll maxx = dinic();
        printf("Case %d: %lld\n",case++,maxx % (m+1));
        for(int i=0;i<=n;i++) v[i].clear();
    }

	return 0;
}