您的位置:首页 > 其它

hdu 1827 Summer Holiday

2013-11-15 10:19 190 查看
用tarjan算法,先对各个极大强连通图进行缩点同时记录缩点中话费最少的值,然后看每一个缩点的入度,如果入度为0,那么说明需要给这个缩点打电话。

#include <iostream>
#include<vector>
#include<stdio.h>
#include<cstring>
#include<algorithm>
#define INF 100000000
using namespace std;
vector<int> map[20005];

int n,m,now,cnt,sum1,sum2,top,num,ans;
int dfn[20005],low[20005],stack[20005],Stack[20005],belong[20005],to[20005],c[10005];
int mini[10005];
void tarjan(int a){
dfn[a]=low[a]=++now;
int u;
stack[++top]=a; //如果用标准库中自带的stack会超时,用这个数组模拟栈
Stack[a]=1; //注意我用大写Stack表示是否在栈中,小写s模拟栈
for(int i=0;i<map[a].size();i++){
u=map[a][i];
if(!dfn[u]){
tarjan(u);
low[a]=min(low[a],low[u]);
}
else if(Stack[u])
low[a]=min(low[a],dfn[u]);
}
if(low[a]==dfn[a]){
int temp;
cnt++;
do{
temp=stack[top--];
belong[temp]=cnt;
if(c[temp]<mini[cnt])
mini[cnt]=c[temp];
Stack[temp]=0;
}while(temp!=a);
}
}

void fun(){
for(int i=1;i<=n;i++){
for(int j=0;j<map[i].size();j++){
int k=map[i][j];
if(belong[i]!=belong[k]){ //相邻两个点不属于同一缩点
to[belong[k]]++;
}
}
}
for(int i=1;i<=cnt;i++){
if(!to[i]){ //入度为0
ans+=mini[i];
num++;}
}
return;
}

int main()
{
while(scanf("%d %d",&n,&m)!=EOF){

cnt=now=sum1=sum2=0;
top=ans=0;
num=0;
memset(dfn,0,sizeof(dfn)); //时间戳
memset(low,0,sizeof(low)); //极大强连通图的最小时间
memset(Stack,0,sizeof(Stack)); //是否在栈中
memset(to,0,sizeof(to)); //缩点的入度
for(int i=1;i<=n;i++){
scanf("%d",&c[i]); //每个点的话费
map[i].clear(); //多组数据一定要写
mini[i]=INF; //每个缩点的最小话费
}
for(int i=1;i<=m;i++){
int a,b;
scanf("%d %d",&a,&b);
map[a].push_back(b);
}
for(int i=1;i<=n;i++){
if(!dfn[i])
tarjan(i);
}
fun();
printf("%d %d\n",num,ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: