本题中文题 题意很明显
问最少要打几个电话
我的做法是强连通+缩点
1A
#include <iostream> #include <cstdio> #include <vector> #include <cstring> #include <algorithm> using namespace std; #define MAXN 1010 int stack[MAXN],low[MAXN],dfn[MAXN],sum[MAXN],tran[MAXN],times,top,m,n; bool instack[MAXN]; int ru[MAXN]; vector <int> e[MAXN]; void tarjan(int u){ low[u]=dfn[u]=++times; stack[top++]=u; instack[u]=true; for(int i=0;i<(int)e[u].size();i++){ int v=e[u][i]; if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(instack[v]) low[u]=min(low[u],low[v]); } if(dfn[u]==low[u]){ int tot=0; ++sum[0]; do{ u=stack[--top]; instack[u]=false; tran[u]=sum[0]; ++tot; }while(dfn[u]!=low[u]); sum[sum[0]]=tot; } } void init(){ for(int i=0;i<MAXN;i++)e[i].clear(); memset(instack,0,sizeof(instack)); memset(tran,0,sizeof(tran)); memset(low,0,sizeof(low)); memset(dfn,0,sizeof(dfn)); memset(ru,0,sizeof(ru)); sum[0]=times=top=0; } int cost[MAXN]; int mincost[MAXN]; int main() { while(~scanf("%d%d",&n,&m)){ init(); for(int i=1;i<=n;i++) scanf("%d",&cost[i]); for(int i=0,x,y;i<m;i++){ scanf("%d%d",&x,&y); e[x].push_back(y); } for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i); for(int i=1;i<=n;i++){ for(int j=0;j<(int)e[i].size();j++){ int v=e[i][j]; if(tran[i]!=tran[v]){ ru[tran[v]]=1; } } } for(int i=1;i<=n;i++) mincost[i]=1000000000; for(int i=1;i<=n;i++){ if(mincost[tran[i]]>cost[i]&&ru[tran[i]]==0)mincost[tran[i]]=cost[i]; } int sumx=0; int count0=0; for(int i=1;i<=sum[0];i++){ if(ru[i]==0){ count0++; sumx+=mincost[i]; } } printf("%d %d\n",count0,sumx); } return 0; }
|