HDU3639Hawk-and-Chicken (好题,强连通缩点,建图,DFS回溯)
2015-08-28 13:12
375 查看
题意:大家玩老鹰抓小鸡的游戏,但是大家都想做老鹰,所以老师安排一个投票,每个人不能投自己,但是可以投多个人,投票具有传递性,比如A–>B, B–>C,那么B获得A一票,C获得B一票,A一票,共计2票。现在问谁能胜出,并列的也算,输出胜出者的票数,以及升序输出,获胜的编号。
思路:由于大家投票,可能有环,所以需要Tarjan算法把图转换为DAG,然后进行搜索,但是如果缩点后正向建图,搜索时会发现,如果一个点有多条路径到达,会出现重复计数,所以反向建图,因为,最终获胜的人,肯定是叶子结点,所以我们从叶子节点反向建图,用DFS搜索,回溯的时候更新,就不会出现重复计数。
思路:由于大家投票,可能有环,所以需要Tarjan算法把图转换为DAG,然后进行搜索,但是如果缩点后正向建图,搜索时会发现,如果一个点有多条路径到达,会出现重复计数,所以反向建图,因为,最终获胜的人,肯定是叶子结点,所以我们从叶子节点反向建图,用DFS搜索,回溯的时候更新,就不会出现重复计数。
#include<cstdio> #include<iostream> #include<algorithm> #include<cmath> #include<set> #include<map> #include<string> #include<cstring> #include<stack> #include<queue> #include<vector> #include<cstdlib> #define lson (rt<<1),L,M #define rson (rt<<1|1),M+1,R #define M ((L+R)>>1) #define cl(a,b) memset(a,b,sizeof(a)); #define LL long long #define P pair<int,int> #define X first #define Y second #define pb push_back #define fread(zcc) freopen(zcc,"r",stdin) #define fwrite(zcc) freopen(zcc,"w",stdout) using namespace std; const int maxn=50005; const int inf=999999; vector<int> belong2[maxn];//属于某一块的连通图的所有节点集合 vector<int> ans;//答案 int dp[maxn];//保存缩点后每个“点”的权值 vector<int> G[maxn]; int low[maxn],dfn[maxn],s[maxn],belong[maxn]; bool ins[maxn]; int num,cnt,top; void dfs(int u){ low[u]=dfn[u]=++num; s[top++]=u; ins[u]=true; int N=G[u].size(); for(int i=0;i<N;i++){ int v=G[u][i]; if(!dfn[v]){ dfs(v); low[u]=min(low[u],low[v]); } else if(ins[v]&&dfn[v]<low[u]){ low[u]=dfn[v]; } } if(low[u]==dfn[u]){ int v=-1; cnt++; while(u!=v){ v=s[--top]; ins[v]=false; belong[v]=cnt; belong2[cnt].pb(v); } } } void Tarjan(int n){ num=cnt=top=0; cl(ins,false); cl(belong,0); cl(dfn,0); for(int i=1;i<=n;i++)if(!dfn[i]){ dfs(i); } } int out[maxn];//出度 vector<int> G2[maxn];//缩点,后的图 int en[maxn];//达到当前点,所能获得的最大票数 int myans; bool vis[maxn];//标记 void dfs2(int u){ int N=G2[u].size(); for(int i=0;i<N;i++){ if(vis[G2[u][i]])continue; vis[G2[u][i]]=true; dfs2(G2[u][i]); myans+=dp[G2[u][i]]+1;//回溯的时候更新,到这个点的最大值 } } int t[maxn]; int main(){ //fread("Text/in.txt"); int T; scanf("%d",&T); int cas=1; while(T--){ int n,m; scanf("%d%d",&n,&m); for(int i=0;i<=n;i++){ G[i].clear(); belong2[i].clear(); G2[i].clear(); } ans.clear(); for(int i=0;i<m;i++){ int x,y; scanf("%d%d",&x,&y); x++;y++; G[x].pb(y); } Tarjan(n); for(int i=1;i<=cnt;i++){ dp[i]=belong2[i].size()-1; } cl(out,0); for(int u=1;u<=n;u++){ for(int j=0;j<G[u].size();j++){ int v=G[u][j]; if(belong[u]!=belong[v]){ out[belong[u]]++; G2[belong[v]].pb(belong[u]);//缩点,建立反向图 // printf("belong[v] = %d ,belng[u] = %d\n",belong[v],belong[u]); } } } cl(en,0); for(int i=1;i<=cnt;i++)if(out[i]==0){//从出度是0的点,也就是叶子节点,计算每个叶子节点的值 myans=0; cl(vis,false); dfs2(i); en[i]=myans; //printf("i = %d, myans = %d\n",i,myans); } int mx=0; cl(t,0); for(int i=1;i<=n;i++){ t[i]=en[belong[i]]+dp[belong[i]];//t[i],是最终的叶子节点的值 mx=max(mx,t[i]); } for(int i=1;i<=n;i++)if(t[i]==mx){ ans.pb(i); } sort(ans.begin(),ans.end()); printf("Case %d: %d\n",cas++,mx); printf("%d",ans[0]-1); for(int i=1;i<ans.size();i++){ printf(" %d",ans[i]-1); } printf("\n"); } return 0; }
相关文章推荐
- meta-data in the Android
- SVN (TortioseSVN) 版本控制之忽略路径(如bin、obj、gen)
- SQL SERVER数据库新认识的一些基础知识
- hadoop集群HA模式的切换尝试初识
- 使用list和tuple
- web压力测试工具 压力测试 webbench
- UVALive 3664 Guess(贪心+精度)
- Java Socket例程3 UDP
- 试试K64的CAN功能
- C++ sizeof用法
- jquery <li>标签 隔若干行 加空白或者加虚线
- TimeButton
- 数据结构与算法分析Java版练习1.3
- USACO 2011 Open Silver 1.Corn Maze (bfs)
- 近期计划
- java状态模式
- C++ * a和*&a作为函数的参数时有什么区别
- USACO 1.1 Your Ride Is Here
- OpenStack Mnaila 2015-08-27 IRC会议内容
- php的一些心得