hdu 1827 Summer Holiday tarjan+缩点
题意:http://acm.hdu.edu.cn/showproblem.php?pid=1827
Summer Holiday
Time Limit: 10000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2050 Accepted Submission(s): 939
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计算出至少要通知多少人,至少得花多少电话费就能让全部人都被通知到吗?
第一行两个整数N和M(1<=N<=1000, 1<=M<=2000),表示人数和联系对数。
接下一行有N个整数,表示Wiskey联系第i个人的电话费用。
接着有M行,每行有两个整数X,Y。表示X能联系到Y,可是不表示Y也能联系X。
每一个CASE输出答案一行。
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
3 6
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #include<vector> int min(int a,int b) { return a>b?b:a; } #define N 1010 //N为最大点数 #define M 2010 //M为最大边数 int n, m;//n m 为点数和边数 struct Edge{ int from, to, nex; bool sign;//是否为桥 }edge[M<<1]; int head[N], edgenum; void add(int u, int v){//边的起点和终点 Edge E={u, v, head[u], false}; edge[edgenum] = E; head[u] = edgenum++; } int DFN[N], Low[N], Stack[N], top, Time; //Low[u]是点集{u点及以u点为根的子树} 中(全部反向弧)能指向的(离根近期的祖先v) 的DFN[v]值(即v点时间戳) int taj;//连通分支标号,从1開始 int Belong[N];//Belong[i] 表示i点属于的连通分支 bool Instack[N]; vector<int> bcc[N]; //标号从1開始 void tarjan(int u ,int fa) { DFN[u] = Low[u] = ++ Time ; Stack[top ++ ] = u ; Instack[u] = 1 ; for (int i = head[u] ; ~i ; i = edge[i].nex ) { int v = edge[i].to; if(DFN[v] == -1) { tarjan(v , u); Low[u] = min(Low[u] ,Low[v]) ; if(DFN[u] < Low[v]) { edge[i].sign = 1;//为割桥 } } else if(Instack[v]) { Low[u] = min(Low[u] ,DFN[v]) ; } } if(Low[u] == DFN[u]) { int now; taj ++ ; bcc[taj].clear(); do{ now = Stack[-- top] ; Instack[now] = 0 ; Belong [now] = taj ; bcc[taj].push_back(now); }while(now != u) ; } } void tarjan_init(int all){ memset(DFN, -1, sizeof(DFN)); memset(Instack, 0, sizeof(Instack)); top = Time = taj = 0; for(int i=1;i<=all;i++) if(DFN[i]==-1 ) tarjan(i, i); //注意開始点标!!
!
} vector<int>G[N]; int du[N]; //入度 void suodian(){ memset(du, 0, sizeof(du)); for(int i = 1; i <= taj; i++) G[i].clear(); for(int i = 0; i < edgenum; i++) { int u = Belong[edge[i].from], v = Belong[edge[i].to]; if(u!=v) { G[u].push_back(v), du[v]++; } } } void init(){memset(head, -1, sizeof(head)); edgenum=0;} int spd[1010]; int main() { while(~scanf("%d%d",&n,&m)) { init(); for(int i=1;i<=n;i++) { scanf("%d",&spd[i]); } for(int i=0;i<m;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v); } tarjan_init(n); suodian(); int numb=0; int ans=0; for(int i=1;i<=taj;i++) { if(du[i]==0&&bcc[i].size()) { int minn=-19999; for(int j=0;j<bcc[i].size();j++) { if(spd[bcc[i][j]]<minn||minn==-19999) { minn=spd[bcc[i][j]]; } } ans+=minn; numb++; } } printf("%d %d\n",numb,ans); } return 0; }