|
Summer Holiday
Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3540 Accepted Submission(s): 1617 Problem Description
To see a World in a Grain of Sand
And a Heaven in a Wild Flower, Hold Infinity in the palm of your hand And Eternity in an hour. —— William Blake 听说lcy帮大家预定了新马泰7日游,Wiskey真是高兴的夜不能寐啊,他想着得快点把这消息告诉大家,虽然他手上有所有人的联系方式,但是一个一个联系过去实在太耗时间和电话费了。他知道其他人也有一些别人的联系方式,这样他可以通知其他人,再让其他人帮忙通知一下别人。你能帮Wiskey计算出至少要通知多少人,至少得花多少电话费就能让所有人都被通知到吗? Input
多组测试数组,以EOF结束。
第一行两个整数N和M(1<=N<=1000, 1<=M<=2000),表示人数和联系对数。 接下一行有N个整数,表示Wiskey联系第i个人的电话费用。 接着有M行,每行有两个整数X,Y,表示X能联系到Y,但是不表示Y也能联系X。 Output
输出最小联系人数和最小花费。
每个CASE输出答案一行。 |
#include <bits/stdc++.h>
using namespace std;
#define mst(a,b) memset(a,(b),sizeof(a))
#define f(i,a,b) for(int i=a;i<=b;i++)
#define maxn 2005
const int INF=2e9;
vector<int>mp[maxn];
int n,m,num,top,suo;
int dfn[maxn],low[maxn],w[maxn],belong[maxn],stack_[maxn],cost[maxn];
bool instack_[maxn],ru[maxn];
void tarjan(int u)
{
dfn[u]=low[u]=++num;
stack_[++top]=u;
instack_[u]=true;
int v;
for(int i=0;i<mp[u].size();i++)
{
v=mp[u][i];
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(instack_[v])
low[u]=min(low[u],dfn[v]);
}
if (low[u]==dfn[u])
{
suo++;
do
{
v=stack_[top--];
belong[v]=suo;
instack_[v]=false;
}while(v!=u);
}
}
void solve()
{
int v;
mst(dfn,0);
mst(instack_,false);
num=top=suo=0;
f(i,1,n)
{
if(!dfn[i])
tarjan(i);
}
mst(ru,false);
f(i,1,n)
{
for(int j=0;j<mp[i].size();j++)
{
v=mp[i][j];
if(belong[i]!=belong[v])
ru[belong[v]]=true;
}
}
f(i,1,suo)
cost[i]=INF;
f(i,1,n)
{
if(!ru[belong[i]])
cost[belong[i]]=min(cost[belong[i]],w[i]);
}
int sum1=0,sum2=0;
f(i,1,suo)
{
if(!ru[i])
{
sum1++;
sum2+=cost[i];
}
}
printf("%d %d\n",sum1,sum2);
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
f(i,1,n)
{
scanf("%d",&w[i]);
mp[i].clear();
}
int x,y;
f(i,1,m)
{
scanf("%d%d",&x,&y);
mp[x].push_back(y);
}
solve();
}
return 0;
}