F - Teen Girl Squad
题目主要是最小树形图, 用朱刘算法求解。
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 1005;
struct nede
{
int u;
int v;
int cost;
} Edge[maxn*maxn];
int pre[maxn], visit[maxn], id[maxn];
double in[maxn];
int zhuliu(int root, int n, int m)
{
double res = 0;
int v;
while(1)
{
for(int i=0; i<n; i++)//到达当前点的最小权值,先初始化
in[i] = INF;
for(int i=0; i<m; i++)//遍历每一个边
{
if(Edge[i].u!=Edge[i].v&&Edge[i].cost<in[Edge[i].v])//如果是一个边并且权值小于到达当前点的权值,更新
{
pre[Edge[i].v] = Edge[i].u;//pre记录前一个点,也就是从哪一点到达当前点
in[Edge[i].v] = Edge[i].cost;//更新权值
}
}
for(int i=0; i<n; i++)//遍历每一个节点
{
if(i!=root&&in[i]==INF)//如果当前点不是根节点,但入度值最小为INF,也就是没有任何边指向此点,那么就不存在最小树形图
return -1;//返回-1
}
memset(id, -1, sizeof(id));//记录环的标号
memset(visit, -1, sizeof(visit));//是否访问过
int tn = 0;//环数
in[root] = 0;//根节点清零
for(int i=0; i<n; i++)//遍历每个节点,求最短弧的集合
{
res += in[i];//加入权值
int v = i;
while(visit[v]!=i&&id[v]==-1&&v!=root)//如果当前点没有被访问过,并且不是根节点,并且不在任何一个环上
{
visit[v] = i;
v = pre[v];
}
if(id[v]==-1&&v!=root)
{
for(int u=pre[v]; u!=v; u=pre[u])
{
id[u] = tn;
}
id[v] = tn++;
}
}
if(tn==0)//没有环出现,则找到了最小树形图
break;//跳出
for(int i=0; i<n; i++)//收缩有向环
{
if(id[i]==-1)
{
id[i] = tn++;
}
}
for(int i=0; i<m;)
{
v = Edge[i].v;
// int u = Edge[i].u;
Edge[i].u = id[Edge[i].u];
Edge[i].v = id[Edge[i].v];
if(Edge[i].u!=Edge[i].v)
Edge[i++].cost -= in[v];
else
swap(Edge[i], Edge[--m]);
}
n = tn;
root = id[root];
}
return res;
}
int main()
{
int T;
scanf("%d", &T);
for(int t = 1;t<=T;t++)
{
int n, m;
scanf("%d %d", &n, &m);
for(int k=0;k<m;k++)
{
scanf("%d %d %d", &Edge[k].u, &Edge[k].v, &Edge[k].cost);
if(Edge[k].u==Edge[k].v)
Edge[k].cost = INF;
}
int res = zhuliu(0, n, m);
if(res==-1)
printf("Case #%d: Possums!\n", t);
else
printf("Case #%d: %d\n", t, res);
}
return 0;
}