题目链接
大佬博客的讲解非常详细,学习了
详细思路见上方博客或者李煜东《算法竞赛进阶指南》
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define _rep(i,a,b) for(int i=(a);i<=(b);i++)
#define _for(i,a,b) for(int i=(a);i<(b);i++)
#define INF 0x3f3f3f3f
const int N=1e3+10;
int n,r;
int cost[N],cnt[N];
int set[N];
bool vis[N];
vector<int>vx[N];
int find()//找出等效权值最大的点
{
double maxn=-INF;
int e;
_rep(i,1,n)
if(!vis[i]&&i!=r&&(double)cost[i]/cnt[i]>maxn)
maxn=(double)cost[i]/cnt[i],e=i;
return e;
}
void unionset(int u,int fu)//合并父子节点
{
cnt[fu]+=cnt[u];
cost[fu]+=cost[u];
for(vector<int>::iterator it=vx[u].begin();it!=vx[u].end();it++)
set[*it]=fu;
}
int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d%d",&n,&r)&&n&&r)
{
int u,v,sum=0;
memset(vis,false,sizeof(vis));
_rep(i,1,n)scanf("%d",&cost[i]),cnt[i]=1,vx[i].clear();
_for(i,1,n)
{
scanf("%d%d",&u,&v);
vx[u].push_back(v);
set[v]=u;
}
_for(i,1,n)
{
u=find();vis[u]=true;
int fu=set[u];
while(vis[fu])fu=set[fu];
sum+=cost[u]*cnt[fu];
unionset(u,fu);
}
printf("%d\n",sum+cost[r]);
}
return 0;
}