Uva1 1391/LA 3713 - Astronauts 构图2-sat...更正了toposort过程...

21 篇文章 0 订阅

            题意:

                     有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;
} 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值