还有这道 POJ 3164 点这传送
题意明确就是求最小树形图.
裸模板,直接上:
/** @Cain*/
const int maxn=1e3;
const int maxm=1e7;
const int inf=1e9;
int n,m;
int cas = 1;
struct edge
{
int u,v,w;
} s[maxn*maxn/2];
int pre[maxn];
int id[maxn];
int vis[maxn];
int in[maxn];
int dirTree(int root,int n,int m)
{ //root为根的编号, n个点, m条边.
int res = 0;
while(1){
for(int i=0;i<n;i++)
in[i] = inf;
for(int i=0;i<m;i++){
int u = s[i].u;
int v = s[i].v;
int w = s[i].w;
if(w < in[v] && u != v){ //找最小入边
in[v] = w;
pre[v] = u;
}
}
in[root] = 0;
for(int i=0;i<n;i++){
if(in[i] != inf)
res += in[i];
else return -1;
}
pre[root] = root;
int newid = 0;
memset(vis,-1,sizeof(vis));
memset(id,-1,sizeof(id));
for(int i=0;i<n;i++){
int u = i;
while(vis[u] != i && id[u] == -1){
vis[u] = i;
u = pre[u];
}
if(u == root || vis[u] != i) continue;
for(int v = pre[u] ; v != u ; v = pre[v] ) //缩点
id[v] = newid;
id[u] = newid++;
}
if(newid == 0) break; //无环
for(int i=0;i<n;i++){
if(id[i] == -1)
id[i] = newid++;
}
for(int i=0;i<m;i++){ //更新边的信息
s[i].w -= in[s[i].v];
s[i].u = id[s[i].u];
s[i].v = id[s[i].v];
}
root = id[root];
n = newid;
}
return res;
}
int main()
{
int t;
cin >> t;
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=0; i<m; i++)
{
scanf("%d%d%d",&s[i].u,&s[i].v,&s[i].w);
}
int res=dirTree(0,n,m);
printf("Case #%d: ",cas++);
if(res == -1)
printf("Possums!\n");
else
printf("%d\n",res);
}
}