大意:有n个宇航员,按照年龄划分,年龄低于平均年龄的是年轻宇航员,而年龄大于等于平均年龄的是老练的宇航员。
现在要分配他们去A,B,C三个空间站,其中A站只有老练的宇航员才能去,而B站是只有年轻的才能去,C站都可以去。
有m对宇航员相互讨厌,不能让他们在同一个空间站工作。
输出每个宇航员应分配到哪个空间站,如果没有则输出No solution.
这道题只要构出图来就很好办啦~~
由于每个宇航员只有两种选择,所以我们可以用一个布尔变量
xi
表示第
i
个宇航员的分配方案(true表示A或B,false表示C)。对于属于不同年龄段的互相讨厌的宇航员
然后用
O(m)
的算法搞搞就行了。
顺便把我写的specialJudge放在这里。输入点数和冲突数(边数),以及每个宇航员的分配方案(A,B,C),还有具体冲突情况(边的端点),输出WA或AC。
顺便提一句:我做了一下试验,拓扑排序不逆序会WA。。。还有不必要删除对立节点所属强连通分量的子孙……
具体关于2-SAT的课件在这里(OTZ)
#include <vector>
#include <stack>
#include <cstdio>
#include <iostream>
#include <cstring>
#define CLR(x) memset(x,0,sizeof x)
#define opp(x) ((((x)-1)^1)+1)
#define pb push_back
using namespace std;
const int maxn=100001<<2,maxm=100001<<2;
typedef int arr[maxn];
int next[maxm],to[maxm];
arr list,pre,lowlink,sccno,q,age,color;
bool visit[maxn];
int n,m,dfsClk,tot,sccCnt,tail;
stack<int>s;
vector<int>scc[maxn];
void dfs(int u){
pre[u]=lowlink[u]=++dfsClk;
s.push(u);
for(int k=list[u];k;k=next[k]){
int v=to[k];
if(!pre[v]){
dfs(v);
lowlink[u]=min(lowlink[u],lowlink[v]);
}
else if(!sccno[v])
lowlink[u]=min(lowlink[u],pre[v]);
}
if(lowlink[u]==pre[u]){
int x;
++sccCnt;
do{
x=s.top();s.pop();
sccno[x]=sccCnt;
}while(x!=u);
}
}
inline void add(int a,int b){
tot++;
next[tot]=list[a];
list[a]=tot;
to[tot]=b;
}
inline void add_clause(int x,int xval,int y,int yval){
x=x+x+xval-1;
y=y+y+yval-1;
add(opp(x),y);add(opp(y),x);
}
void topodfs(int u){
visit[u-2*n]=true;
for(int k=list[u];k;k=next[k])
if(!visit[to[k]-2*n]) topodfs(to[k]);
q[++tail]=u-2*n;
}
inline int read(){
int x=0;
char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch))x=x*10+ch-48,ch=getchar();
return x;
}
inline void init(){
CLR(list);CLR(pre);CLR(sccno);CLR(color);
CLR(visit);
for(int i=0;i<=sccCnt;++i)scc[i].clear();
dfsClk=sccCnt=tot=tail=0;
while(!s.empty())s.pop();
}
inline bool work(){
n=read();m=read();
if(n==0&&m==0) return false;
init();
int a,b;
double ave=0.0;
for(int i=1;i<=n;++i) ave+=(age[i]=read());
ave/=n;
for(int i=1;i<=m;++i){
a=read();b=read();
if((age[a]>=ave)^(age[b]>=ave))
add_clause(a,1,b,1);
else add_clause(a,0,b,0),add_clause(a,1,b,1);
}
for(int i=1;i<=(n<<1);++i)
if(!pre[i])dfs(i);
for(int i=1;i<=n;++i)
if(sccno[i<<1]&&sccno[(i<<1)-1]&&sccno[i<<1]==sccno[(i<<1)-1])
{puts("No solution.");return true;}
for(int i=1;i<=(n<<1);++i){
for(int k=list[i];k;k=next[k]){
if(sccno[i]!=sccno[to[k]])
add(sccno[i]+2*n,sccno[to[k]]+2*n);
}
}
for(int i=2*n+1;i<=sccCnt+2*n;++i)
if(!visit[i-2*n]) topodfs(i);
for(int i=1;i<=(n<<1);++i)
scc[sccno[i]].pb(i);
CLR(visit);
for(int i=tail;i;--i){
int u=q[i],size=scc[u].size();
if(!visit[u]) for(int j=0;j<size;++j){
int cur=opp(scc[u][j]);
color[cur]=1;
visit[sccno[cur]]=true;
}
}
for(int i=1;i<=n;++i){
if(!color[i<<1]) puts(age[i]>=ave?"A":"B");
else puts("C");
}
return true;
}
int main(){
while(work()) ;
}
Special Judge:
#include<bits/stdc++.h>
using namespace std;
set<int>S[3];
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
char ch;
do{ch=getchar();}while(ch!='A'&&ch!='B'&&ch!='C');
S[ch-'A'].insert(i);
}
for(int i=1;i<=m;++i){
int a,b;
scanf("%d%d",&a,&b);
for(int j=0;j<3;++j){
if(S[j].count(a)) a=j;
if(S[j].count(b)) b=j;
}
if(a==b) {puts("Wrong Answer!");return 0;}
}
puts("Accepted!");
return 0;
}