这个题求最小有向生成树,基本上就是朱刘算法模板。
代码:
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
const int inf=1<<29;
const int maxn=1100;
const int maxm=5e4;
struct Edge
{
int u;
int v;
int c;
}E[maxm];
int n,m,pre[maxm],ID[maxm],vis[maxm],cnt[maxn];
int In[maxm];
int Directed_MST(int root,int NV,int NE)
{
int ret=0;
while(1)
{
//1、找最小入边
for(int i=0;i<NV;i++)
In[i]=inf;
for(int i=0;i<NE;i++)
{
int u=E[i].u;
int v=E[i].v;
if(E[i].c<In[v]&&u!=v)
{
pre[v]=u;
In[v]=E[i].c;
}
}
for(int i=0;i<NV;i++)
{
if(i==root)
continue;
if(In[i]==inf)
return -1;
}
//2、找环
int cntnode=0;
memset(ID,-1,sizeof(ID));
memset(vis,-1,sizeof(vis));
In[root]=0;
for(int i=0;i<NV;i++)
{
ret+=In[i];
int v=i;
while(vis[v]!=i&&ID[v]==-1&&v!=root)
{
vis[v]=i;
v=pre[v];
}
if(v!=root&&ID[v]==-1)
{
for(int u=pre[v];u!=v;u=pre[u])
{
ID[u]=cntnode;
}
ID[v]=cntnode++;
}
}
if(cntnode==0)
break;//无环
for(int i=0;i<NV;i++)
if(ID[i]==-1)
{
ID[i]=cntnode++;
}
//3.缩点,重新标记
for(int i=0;i<NE;i++)
{
int v=E[i].v;
E[i].u=ID[E[i].u];
E[i].v=ID[E[i].v];
if(E[i].u!=E[i].v)
{
E[i].c-=In[v];
}
}
NV=cntnode;
root=ID[root];
}
return ret;
}
int main()
{
int T,cas=1;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
memset(cnt,0,sizeof(cnt));
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&E[i].u,&E[i].v,&E[i].c);
cnt[E[i].v]++;
}
int ans=Directed_MST(0,n,m);
if(ans==-1)
printf("Case #%d: Possums!\n",cas++);
else
printf("Case #%d: %d\n",cas++,ans);
}
return 0;
}