题意:
有N个宇航员要登录星球..大于等于平均年龄的宇航员是老宇航员...后则是小宇航员...老宇航员能登陆A,C星球..小宇航员能登录B,C星球..而有些对宇航员间有矛盾..不能登录同一个星球...请找出任意可行的一种登陆方案...
题解:
由于老宇航员和小宇航员都共有C...那么首先看作两个状态..登陆C或者不登陆C..所以对于一对敌对关系<a,b>有
1、当a登陆c时..b不能登陆c...b登录c时a不能登录c...这样可以构造两条有向边
2、当a,b是同一年龄段的..那么当a不登陆c时..b一定要登陆c...b不登录c时..a一定又登陆c...这样在条件下再构造两条有向边...
然后就跑tarjan..判断可行性并且缩点..然后用toposort找出一组可行解...输出的时候..当老宇航员是非C时输出A..小宇航员非C时输出B..不论大小..是C时输出C...
这道题更新了toposort的过程..总算不是那么有漏洞和暴力了...思想是缩点后构造反向边...然后从反向边的图中入度为0的点开始标记(也就是原图中出度为0的点)...标记的过程中...将它自己标记成"拿"..将与其相斥的点染成"不拿"...这里很有意思..对于一个缩了的点..我是以为它会有多个冲突的点..但是实践证明它只有至多一个相互冲突的点..那直接用个数组存下其标号就行了...
Program:
#include<iostream> #include<stdio.h> #include<cmath> #include<queue> #include<stack> #include<string.h> #include<map> #include<set> #include<algorithm> #define oo 1000000007 #define MAXN 100005<<1 #define MAXM 100000<<2 #define ll long long using namespace std; struct node { int x,y,next; }line[MAXM]; int Lnum,_next[MAXN],age[MAXN],dfn[MAXN],low[MAXN],tp[MAXN],tpnum,DfsIndex; int color[MAXN],d[MAXN],opp[MAXN]; bool old[MAXN],instack[MAXN]; set<int> T[MAXN]; stack<int> mystack; queue<int> myqueue; void addline(int x,int y) { line[++Lnum].next=_next[x],_next[x]=Lnum; line[Lnum].x=x,line[Lnum].y=y; } void tarjan(int x) { instack[x]=true,mystack.push(x); dfn[x]=low[x]=++DfsIndex; for (int k=_next[x];k;k=line[k].next) { int y=line[k].y; if (!dfn[y]) { tarjan(y); low[x]=min(low[x],low[y]); }else if (instack[y]) low[x]=min(low[x],dfn[y]); } if (low[x]==dfn[x]) { tpnum++; do { x=mystack.top(); mystack.pop(); instack[x]=true; tp[x]=tpnum; }while (low[x]!=dfn[x]); } } bool judge(int N) { for (int i=0;i<N;i++) if (tp[i<<1]==tp[i<<1|1]) return false; return true; } void toposort(int N) { int i,h; memset(color,0,sizeof(color)); while (!myqueue.empty()) myqueue.pop(); for (i=1;i<=N;i++) if (!d[i]) myqueue.push(i); while (!myqueue.empty()) { h=myqueue.front(); myqueue.pop(); if (color[h]) continue; color[h]=1,color[opp[h]]=2; set<int>::iterator it; for (it=T[h].begin();it!=T[h].end();it++) { d[*it]--; if (!d[*it]) myqueue.push(*it); } } } int main() { int N,M,i,sum,v; freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); while (~scanf("%d%d",&N,&M) && (N || M)) { sum=0; for (i=0;i<N;i++) scanf("%d",&age[i]),sum+=age[i]; Lnum=0,memset(_next,0,sizeof(_next)); v=(int)(sum*1.0/N); if (v*N<sum) v++; memset(old,false,sizeof(old)); for (i=0;i<N;i++) if (age[i]>=v) old[i]=true; while (M--) { int x,y; scanf("%d%d",&x,&y); addline(x<<1,y<<1|1),addline(y<<1,x<<1|1); //x<<1选c...x<<1|1不选 if (old[x]^old[y]==0) addline(x<<1|1,y<<1),addline(y<<1|1,x<<1); } memset(dfn,0,sizeof(dfn)); memset(instack,false,sizeof(instack)); while (!mystack.empty()) mystack.pop(); tpnum=DfsIndex=0; for (i=0;i<(N<<1);i++) if (!dfn[i]) tarjan(i); if (!judge(N)) { printf("No solution.\n"); continue; } for (i=1;i<=tpnum;i++) T[i].clear(); for (i=0;i<(N<<1);i++) opp[tp[i]]=tp[i^1]; memset(d,0,sizeof(d)); for (i=1;i<=Lnum;i++) { int x=tp[line[i].x],y=tp[line[i].y]; if (x==y || T[y].count(x)) continue; T[y].insert(x); d[x]++; } toposort(tpnum); for (i=0;i<N;i++) { if (color[tp[i<<1]]==1) printf("C\n"); else if (old[i]) printf("A\n"); else printf("B\n"); } } return 0; }