HDU

先上题目:

Summer Holiday

Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1337    Accepted Submission(s): 607


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输出答案一行。
 
Sample Input
12 16
2 2 2 2 2 2 2 2 2 2 2 2
1 3
3 2
2 1
3 4
2 4
3 5
5 4
4 6
6 4
7 4
7 12
7 8
8 7
8 9
10 9
11 10
 
Sample Output
3 6
 
  中文题意不解释。这一条题需要使用缩点,对于同一个强连通分量里面因为任何的点都是可达的,所以对于这一个强连通分量里面的点,只需要找花费最小的那个点就可以了。同时不同的强连通分量之间也可能会有边相连,所以缩点以后,我们只需要找出缩点入度为零的点,这些位置就是需要联系的人。同时还需要注意给出的数据有可能是一个森林。
  这里我用了Tarjan缩点,第一次使用,还是有点地方不是很熟悉,或者说还有一点地方不是很了解。
  需要注意一下的地方有:①同一个强连通分量里面的点的low不一定是一样的。②节点是否已经访问和节点是否在栈中并不是等价的,所以需要分开来判断。
  关于强连通分量,还需要训练一下,再总结一下。
 
上代码:
 
  1 #include <cstdio>
  2 #include <cstring>
  3 #include <stack>
  4 #define min(x,y) (x < y ? x : y)
  5 #define MAX 2002
  6 #define INF 1000000000
  7 using namespace std;
  8 
  9 int n,m,id,index;
 10 int p[MAX>>1];
 11 int c[MAX>>1];
 12 int belong[MAX>>1];
 13 int dfn[MAX>>1],low[MAX>>1];
 14 bool instack[MAX>>1];
 15 
 16 stack<int> s;
 17 typedef struct{
 18     int from;
 19     int to;
 20     int next;
 21 }Edge;
 22 Edge e[MAX];
 23 int tot;
 24 int in[MAX>>1],les[MAX>>1];
 25 
 26 void add(int u,int v){
 27     e[tot].next=p[u];   e[tot].from=u;  e[tot].to=v;    p[u]=tot++;
 28 }
 29 
 30 void reset(){
 31     id=0;
 32     index=0;
 33     while(!s.empty()) s.pop();
 34     memset(c,0,sizeof(c));
 35     memset(p,-1,sizeof(p));
 36     memset(e,0,sizeof(e));
 37     memset(belong,0,sizeof(belong));
 38     memset(dfn,0,sizeof(dfn));
 39     memset(low,0,sizeof(low));
 40     memset(in,0,sizeof(in));
 41     memset(instack,0,sizeof(instack));
 42     tot=0;
 43 }
 44 
 45 void tarjan(int u){
 46     dfn[u]=low[u]=++id;
 47     s.push(u);
 48     instack[u]=1;
 49     for(int v=p[u];v!=-1;v=e[v].next){
 50         if(dfn[e[v].to]==0){
 51             tarjan(e[v].to);
 52             low[u]=min(low[u],low[e[v].to]);
 53         }else if(instack[e[v].to]){
 54             low[u]=min(low[u],dfn[e[v].to]);
 55         }
 56     }
 57     if(dfn[u]==low[u]){
 58         int v;
 59         index++;
 60         les[index]=c[u];
 61         do{
 62             v=s.top();
 63             belong[v]=index;
 64             les[index]=min(les[index],c[v]);
 65             instack[v]=0;
 66             s.pop();
 67         }while(u!=v);
 68     }
 69 }
 70 
 71 int main()
 72 {
 73     int x,y,minn,count;
 74     //freopen("data.txt","r",stdin);
 75     while(scanf("%d %d",&n,&m)!=EOF){
 76         reset();
 77         for(int i=1;i<=n;i++){
 78                 scanf("%d",&c[i]);
 79         }
 80         for(int i=1;i<=m;i++){
 81                 scanf("%d %d",&x,&y);
 82                 add(x,y);
 83         }
 84         for(int i=1;i<=n;i++){
 85             if(dfn[i]<=0) tarjan(i);
 86         }
 87         for(int i=0;i<tot;i++){
 88             int u,v;
 89             u=belong[e[i].from];
 90             v=belong[e[i].to];
 91             if(u!=v){
 92                 in[v]++;
 93             }
 94         }
 95         minn=0;
 96         count=0;
 97         for(int i=1;i<=index;i++){
 98             if(in[i]==0){
 99                 minn+=les[i];
100                 count++;
101             }
102         }
103         printf("%d %d
",count,minn);
104     }
105     return 0;
106 }
1827
原文地址:https://www.cnblogs.com/sineatos/p/3595321.html