zoukankan      html  css  js  c++  java
  • [NOI2017]游戏

    题目大意:
      有n(n<=50000)场赛车游戏,每场游戏有不同的赛车,总共有ABC三种不同的场地。
      赛车对使用场地有要求,a型赛车不能在A上开,b型赛车不能在B上开,c型赛车不能在C上开,x型赛车可以在任何赛场上开。
      x型赛车恰好有d(d<=8)种。
      特别地,还有m(m<=100000)条特殊规定,如果第i场游戏的场地为hi,那么第j场游戏一定要在hj号场地上。
      问是否存在完成游戏的方案,并求出任意一种方案。

    思路:
      事实上两种不同的赛车就可以涵盖所有类型的场地,因此我们只需要2^d枚举一下每一个x型赛车属于a型还是b型。
      对于每一场游戏,由于已经限制某种场地不能选,因此每一场只有2种情况。
      这样就转化成了一个2-SAT问题。
      对于m条限制,我们可以分类讨论判断连边方式。
        1.若s[i]=hi,第i张地图本来就不适合u车,说明u车一定无解,不连任何边。
        2.若s[j]=hj,第i张地图适合u车,但第j张地图不适合v车,就用u->u’
        3.若s[i]≠hi且s[j]≠hj,两张地图都适合,那么连边u->v,再连边v′->u′,表示第j张地图如果选用v′那么第i张地图不能用u,即用u′。
      然后Tarjan判断一下是否会有矛盾出现即可。
      最后构造方案时,由于是任意一种方案,因此我们可以对于同一场游戏,选SCC编号小的。可以证明这样一定是正确的(然而我并不会证)。
      UOJ上有一组Ext数据,所以一直被卡成97分,不过不能用正常方法过掉这组数据,
      只能舍弃一些状态,比如卡时间或者随机枚举100种状态(并不能保证正确性),所以最后还是交洛谷上了。

      1 #include<stack>
      2 #include<cstdio>
      3 #include<cctype>
      4 #include<vector>
      5 inline int getint() {
      6     register char ch;
      7     while(!isdigit(ch=getchar()));
      8     register int x=ch^'0';
      9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
     10     return x;
     11 }
     12 inline char gettype() {
     13     register char ch;
     14     while(!isupper(ch=getchar()));
     15     return tolower(ch);
     16 }
     17 const int N=50000,M=100000,D=8;
     18 char s[N];
     19 bool ins[N<<1];
     20 std::stack<int> stack;
     21 std::vector<int> e[N<<1];
     22 int n,d,m,pos[N],dfn[N<<1],low[N<<1],scc[N<<1],cnt,id;
     23 struct Limit {
     24     int i;
     25     char hi;
     26     int j;
     27     char hj;
     28 };
     29 Limit lim[M];
     30 inline void add_edge(const int &u,const int &v) {
     31     e[u].push_back(v);
     32 }
     33 inline void reset() {
     34     while(!stack.empty()) stack.pop();
     35     cnt=id=0;
     36     for(register int i=0;i<n<<1;i++) {
     37         e[i].clear();
     38         dfn[i]=ins[i]=0;
     39     }
     40 }
     41 inline void tarjan(const int &x) {
     42     stack.push(x);
     43     ins[x]=true;
     44     dfn[x]=low[x]=++cnt;
     45     for(unsigned i=0;i<e[x].size();i++) {
     46         const int &y=e[x][i];
     47         if(!dfn[y]) {
     48             tarjan(y);
     49             low[x]=std::min(low[x],low[y]);
     50         } else if(ins[y]) {
     51             low[x]=std::min(low[x],dfn[y]);
     52         }
     53     }
     54     if(low[x]==dfn[x]) {
     55         id++;
     56         int y=-1;
     57         while(y!=x) {
     58             y=stack.top();
     59             stack.pop();
     60             ins[y]=false;
     61             scc[y]=id;
     62         }
     63     }
     64 }
     65 inline int getpos(const int &x,const char &y) {
     66     if(s[x]=='a') {
     67         if(y=='b') return x<<1;
     68         if(y=='c') return x<<1|1;
     69     }
     70     if(s[x]=='b') {
     71         if(y=='a') return x<<1;
     72         if(y=='c') return x<<1|1;
     73     }
     74     if(s[x]=='c') {
     75         if(y=='a') return x<<1;
     76         if(y=='b') return x<<1|1;
     77     }
     78     return 0;
     79 }
     80 inline char getval(const int &x,const bool &y) {
     81     if(s[x]=='a') {
     82         if(y==false) return 'B';
     83         if(y==true) return 'C';
     84     }
     85     if(s[x]=='b') {
     86         if(y==false) return 'A';
     87         if(y==true) return 'C';
     88     }
     89     if(s[x]=='c') {
     90         if(y==false) return 'A';
     91         if(y==true) return 'B';
     92     }
     93     return 0;
     94 }
     95 inline bool solve() {
     96     for(register int i=0;i<m;i++) {
     97         if(s[lim[i].i]==lim[i].hi) continue;
     98         const int u=getpos(lim[i].i,lim[i].hi),v=getpos(lim[i].j,lim[i].hj);
     99         if(s[lim[i].j]==lim[i].hj) add_edge(u,u^1);
    100         if(s[lim[i].i]!=lim[i].hi&&s[lim[i].j]!=lim[i].hj) {
    101             add_edge(u,v);
    102             add_edge(v^1,u^1);
    103         }
    104     }
    105     for(register int i=0;i<n<<1;i++) {
    106         if(!dfn[i]) tarjan(i);
    107     }
    108     for(register int i=0;i<n;i++) {
    109         if(scc[i<<1]==scc[i<<1|1]) return false;
    110     }
    111     for(register int i=0;i<n;i++) {
    112         putchar(getval(i,scc[i<<1]>=scc[i<<1|1]));
    113     }
    114     return true;
    115 }
    116 int main() {
    117     n=getint(),d=getint();
    118     scanf("%s",s);
    119     for(register int i=0,cnt=0;i<n;i++) {
    120         if(s[i]=='x') pos[cnt++]=i;
    121     }
    122     m=getint();
    123     for(register int i=0;i<m;i++) {
    124         lim[i]=(Limit){getint()-1,gettype(),getint()-1,gettype()};
    125     }
    126     for(register int k=0;k<1<<d;k++) {
    127         for(register int i=0;i<d;i++) {
    128             s[pos[i]]='a'+(k>>i&1);
    129         }
    130         if(solve()) return 0;
    131         reset();
    132     }
    133     puts("-1");
    134     return 0;
    135 }
  • 相关阅读:
    使用boost中的property_tree实现配置文件
    C++ 中使用boost::property_tree读取解析ini文件
    引用计数的原理和实例
    C++智能指针(auto_ptr)详解
    Oracle数据库用户锁定原因以及处理方式(ORA-28000)
    Address already in use : connect 的解决办法
    JMeter之Ramp-up Period(in seconds)说明(可同时并发)
    JMETER压力测试报错:JAVA.NET.BINDEXCEPTION: ADDRESS ALREADY IN USE: CONNECT
    spring cloud学习填坑笔记
    使用JMeter进行一次简单的带json数据的post请求测试,json可配置参数
  • 原文地址:https://www.cnblogs.com/skylee03/p/8185647.html
Copyright © 2011-2022 走看看