uva12163 - Addition-Subtraction Game SG函数 状态压缩

You and your friend are playing a 2 player game.The game is played in a graph ofV vertices. The vertices are numberedfrom 0 to V-1. The graph has some directed edges. But the graphdoes not contain any cycles or loops. The rule of the game is as follows.

1.     Initiallyvertex i has a positive value valuei

2.     Bothplayers make their moves by turns. In his turn the player chooses a vertex withthe following properties.

·        The value of the vertex is strictly positive.

·        The vertex has one or more outgoing edges.

If there is no such vertex theplayer loses and the game terminates.

3.     If the player canselect a vertex the player will decrease the value of the selected vertexiby 1. Then from the set of vertices which have an incoming edge fromvertexi, the player will select Ki (this value willbe given as input) vertices and increase the value of those vertices by1. Among these selected Ki vertices there can be duplicatedvertices. And if a vertex is selectedn times its value will beincreased by 1 every time. Or in another word its value will beincreased byn. For example if the Ki=6 and theselected vertex set is{2,2,2,3,3,5} then value2 willbe increased by3, value3 will be increasedby 2 and value5 will be increased by 1.

Now consider the graph on theright.

 

Let the values of K be {2,1,3,2}.

 

Now the value set {0,0,0,5}is a losing terminating position because the player cannot select any vertexwhich have outgoing edges and positive values.

For the value set {3,4,5,6}the current player can go to the following value states by1 move.

·        {2,5,6,6} – select the vertex 0, decrease its value by1.And increase both of 1 and 2 by1. Here K0=2.

·        {2,6,5,6} – select the vertex 0, decrease its value by1and increase its adjacent 1 by 2. HereK0=2.

·        {2,4,7,6} – select the vertex 0, decrease its value by1and increase its adjacent 2 by 2. HereK0=2.

·        {3,3,5,7} – select the vertex 1, decrease its value by1and increase its adjacent 3 by 1. HereK1=1.

·        {3,7,4,6} – select the vertex 2, decrease its value by1and increase its adjacent 1 by 3. HereK2=3.

·        {3,5,4,8} – select the vertex 2, decrease its value by1and increase its adjacent 1 by 1 and3 by 2. Here K2=3.

·        {3,6,4,7} – select the vertex 2, decrease its value by1and increase its adjacent 1 by 2 and3 by 1. Here K2=3.

·        {3,4,4,9} – select the vertex 2, decrease its value by 1 andincrease its adjacent 3 by 3. HereK2=3.

Now giventhe graph and initial values of each of the vertices your task is to determineif the first player wins or loses given that both players play perfectly.

 

Input

Input contains multiple number oftest cases. First line contains T(1 ≤T ≤ 20) the number of test cases. Each test case starts with a lineV(2 ≤ V ≤ 100) and E(2 ≤E ≤ 1500). V is the number of vertices andE is thenumber of edges. Each of the next E lines contains2 integers FROM(0 ≤ FROM < V) and TO(0 ≤TO < V) denoting that there is a directed edge fromFROM to TO.FROM and TO will not be equal. Alsoeach vertex will have at most 15 outgoing edges.  Next line containsVintegers K0, K1,… KV-1.Each of the value ofK is between 1 and 100 inclusive.Next line containsR(1 ≤ R ≤100) the number of rounds. There will be R round of game with thisgraph. Each of the nextR lines contains the description of each round.Each round consists ofV integers Value0 Value1…ValueV-1 denoting the initial value of each vertex. Each oftheseValuei will be between 1 and 100inclusive.

 

Output

For each test case output consist of R+1 lines. First line is“Game#i:” where i is the game number. Game number starts from1. Eachof the next R lines contains “Round#j: RESULT” wherej is the number of round. RESULT is either WINNINGwhen the initial values of this round is a winning position for the firstplayer orLOSING when the initial values of this round is a losingposition for the first player. We will assume that both players play perfectly.Print a blank line after the output of each test case. See the output forsample input for more clarification.

 

SampleInput                              Output for Sample Input

2

3 3

1 0

2 0

1 2

0 2 2

5

3 0 0

4 1 0

5 0 1

1 1 1

2 2 2

4 3

0 1

1 2

2 3

3 2 1 0

5

0 0 0 0

0 0 0 1

0 0 1 0

0 1 0 0

1 0 0 0

 

Game#1:

Round#1: LOSING

Round#2: WINNING

Round#3: WINNING

Round#4: WINNING

Round#5: LOSING

 

Game#2:

Round#1: LOSING

Round#2: LOSING

Round#3: WINNING

Round#4: WINNING

Round#5: LOSING

 

  给出一个图,每个点i有个权值,还有个k[i],双方每次选一个点权值减1,再选k[i]个它连接的点,权值加一。谁不能操作就算输。

  这个和那个棋子在图上移动差不多,很多棋子的游戏相当于很多单个棋子游戏的NIM和,先预处理出每个点上单个棋子的SG值,最后全异或上。

  要选k[i]个点这里是难点。因为每个点最多对应15个点,只要枚举选了哪些点奇数次就行了。这里很重要,因为选偶数次SG异或为0,所以只要选的奇数点的个数小于k[i],并且和k[i]同奇偶(不可能说选偶数个点,但有奇数个奇数次的点,反过来也不行),这样就可以不受k[i]很大的困扰了。

   需要注意的是如果开vis数组的话需要开比较大,因为SG可能不止N,如果用vector排序再判断一下可以避免vis数组开小了的问题。

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<algorithm>
#define eps 1e-9
#define MAXN 110
#define MAXM 110
#define MAXNODE 100010*27
#define MOD 999983
typedef long long LL;
using namespace std;
int T,N,M,R,g[MAXN],k[MAXN],cnt[1<<16];
vector<int> V[MAXN];
int SG(int u){
    if(g[u]!=-1) return g[u];
    if(!V[u].size()) return g[u]=0;
    bool vis[100000];   //注意SG不只N,可能很大
    memset(vis,0,sizeof(vis));
    int L=V[u].size();
    for(int i=0;i<L;i++){
        int v=V[u][i];
        if(g[v]==-1) g[v]=SG(v);
    }
    for(int i=0;i<(1<<L);i++){
        if(cnt[i]>k[u]) continue;
        if((cnt[i]^k[u])&1) continue;
        int sg=0;
        for(int j=0;j<L;j++) if(i&(1<<j)) sg^=g[V[u][j]];
        vis[sg]=1;
    }
    for(int i=0;;i++) if(!vis[i]) return g[u]=i;
}
int getbit(int x){
    int ret=0;
    while(x){
        if(x&1) ret++;
        x>>=1;
    }
    return ret;
}
int main(){
    freopen("in.txt","r",stdin);
    int cas=0;
    scanf("%d",&T);
    for(int i=0;i<(1<<16);i++) cnt[i]=getbit(i);
    while(T--){
        printf("Game#%d:\n",++cas);
        scanf("%d%d",&N,&M);
        for(int i=0;i<=N;i++) V[i].clear();
        int u,v;
        while(M--){
            scanf("%d%d",&u,&v);
            V[u].push_back(v);
        }
        memset(g,-1,sizeof(g));
        for(int i=0;i<N;i++) scanf("%d",&k[i]);
        scanf("%d",&R);
        for(int i=1;i<=R;i++){
            int t,sg=0;
            for(int j=0;j<N;j++){
                scanf("%d",&t);
                if(t%2) sg^=SG(j);
            }
            printf("Round#%d: ",i);
            if(sg) printf("WINNING\n");
            else printf("LOSING\n");
        }
        puts("");
    }
    return 0;
}



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值