Optimal Bus Route Design UVA - 1349
题意:
给你n个点(n<=100)的有向带权图,找若干个有向圈,每个点恰好属于一个圈。要求权和尽量小。注意(u,v)和(v,u)都存在,它们的权值不一定相等。
思路:(紫薯)
每个点恰好属于一个有向圈,意味着每一个点都有一个唯一的后继。反过来,只要每个点都有唯一的后继,每个点一定属于一个圈。“每个东西恰好有唯一的。。。”让我们想到了二分图匹配
。把每个点拆成两个。一个在x集合,一个在y集合。
AC
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <queue>
#include <cstdio>
#define pb push_back
#define mst(x,a)
#define sz(a) (int)a.size()
#define For(i,x,y) for(int i=(x); i<=(y); i++)
#define fori(i,x,y) for(int i=(x); i<(y); i++)
#define fzhead EDGE(int u, int v, int c, int f, long long w)
#define fzbody from(u), to(v), cap(c), flow(f), cost(w)
using namespace std;
typedef long long ll;
const int maxn = 200+100;
const ll INF = 0x3f3f3f3f3f3f3f3f;
struct EDGE{
int from, to, cap, flow;
ll cost;
EDGE(){}
fzhead:fzbody{}
};
struct MCMF{
int n, m;
vector<EDGE> edges;
vector<int> G[maxn];
int inq[maxn];
ll d[maxn];///注意这里,这里后面有比较
int p[maxn];
int a[maxn];
///
void init(int n){
this->n = n;
fori(i,0,n)G[i].clear();
edges.clear();
}
void AddEdge(int from, int to, int cap, ll cost){
edges.pb({from, to, cap, 0, cost});
edges.pb({to, from, 0, 0, -cost});
m=edges.size();
G[from].pb(m-2);
G[to].pb(m-1);
}
///
bool BellmanFord(int s,int t, int& flow, ll& cost){
fori(i,0,n) d[i] = INF;
mst(inq,0);
d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;
queue<int>q;
q.push(s);
while(!q.empty()){
int u = q.front(); q.pop();
inq[u] = 0;
fori(i,0,sz(G[u])){
EDGE& e = edges[G[u][i]];
if(e.cap > e.flow && d[e.to] > d[u] + e.cost){
d[e.to] = d[u] + e.cost;
p[e.to] = G[u][i];
a[e.to] = min(a[u], e.cap - e.flow);
if(!inq[e.to]) { q.push(e.to); inq[e.to] = 1;}
}
}
}
if(d[t] == INF)return false ;
flow += a[t];
cost += (ll)d[t] * (ll)a[t];
for(int u = t; u != s; u = edges[p[u]].from){
edges[p[u]].flow += a[t];
edges[p[u]^1].flow -= a[t];
}
return true;
}
///
int MincostMaxflow(int s, int t, ll& cost){
int flow = 0; cost = 0;
while(BellmanFord(s, t, flow, cost));///cout<<flow<<' '<<cost<<endl;
return flow;
}
}mcmf;
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int n;
while(cin>>n,n){
int u, v, dis;
mcmf.init(maxn);
int s = 0, t = n*2 + 1;
For(i,1,n)mcmf.AddEdge(s, i, 1, 0), mcmf.AddEdge(i+n, t, 1, 0);
For(u,1,n){
while(cin>>v){
if(v == 0)break;
cin>>dis;
mcmf.AddEdge(u, v+n, 1, dis);
}
}
ll cost;
if(mcmf.MincostMaxflow(s, t, cost)==n)cout<<cost<<endl;
else cout<<"N"<<endl;
}
return 0;
}