zoukankan      html  css  js  c++  java
  • 最简单的博弈论——HDU

    OK,好的先看一下题意:

    B君在围观一群男生和一群女生玩游戏,具体来说游戏是这样的: 
    给出一棵n个节点的树,这棵树的每条边有一个权值,这个权值只可能是0或1。 在一局游戏开始时,会确定一个节点作为根。接下来从女生开始,双方轮流进行 操作。 
    当一方操作时,他们需要先选择一个不为根的点,满足该点到其父亲的边权为1; 然后找出这个点到根节点的简单路径,将路径上所有边的权值翻转(即0变成1,1 变成0 )。 
    当一方无法操作时(即所有边的边权均为0),另一方就获得了胜利。 
    如果在双方均采用最优策略的情况下,女生会获胜,则输出“Girls win!”,否则输 出“Boys win!”。 
    为了让游戏更有趣味性,在每局之间可能会有修改边权的操作,而且每局游戏指 定的根节点也可能是不同的。 
    具体来说,修改边权和进行游戏的操作一共有m个,具体如下: 
    ∙∙“0 x”表示询问对于当前的树,如果以x为根节点开始游戏,哪方会获得胜利。 
    ∙∙“1 x y z ”表示将x和y之间的边的边权修改为z。

    —————————————————————————————————————————————————————————————————————————————

     sorry,代码在下面

     题意应该比较好懂,一般人应该也知道这是博弈论。

    但是我建议大家先模拟一下样例,方便理解。

    但是具体怎么想呢?

    博弈论一般都要先想什么时候是必胜状态。

    同理:

    这道题的必胜状态是什么呢?

    当根节点所连的边中只有一条边的权值为1的话,那么肯定是 女生赢。

    当根节点只连一条边,且边的权值是1,在这条边之后又连了很多条边,随便编的权值。

    第一次女生翻转,那么第一条边的权值变成了0. 男生肯定不能翻转第一条边,

    如果男生不能翻转,那么女生就赢了,如果男生还可以翻转,这时候第一条边又变成了1.

    女生翻转又把第一条边变成了0.所以男生永远不可能翻转第一条边。

    所以这种状态一定是女生赢。(根节点连了一条权值为1 的边。)

    如果根节点连的边的权值和 为奇数,就是女生赢,反之就是男生赢。

    是不是很简单。

    然后是超级简单的代码。

    提醒大家注意理解sum数组的含义。

     1 #include <cstdio>
     2 #include <cstring>
     3 using namespace std;
     4 const int maxn=40005;
     5 struct node{
     6     int from,to,next,value;
     7 }e[maxn<<1];
     8 int head[maxn],cnt,sum[maxn];
     9 void add(int x,int y,int z){
    10     e[++cnt].from=x;e[cnt].to=y;e[cnt].value=z;e[cnt].next=head[x];head[x]=cnt;
    11 }
    12 int main(){
    13     //freopen("a.in","r",stdin);
    14     int t;scanf("%d",&t);
    15     while(t--){    
    16         memset(e,0,sizeof(e));
    17         memset(head,0,sizeof(head));
    18         memset(sum,0,sizeof(sum));
    19         cnt=0;
    20         int n,m;scanf("%d%d",&n,&m);
    21         for(int i=1;i<n;i++){
    22             int x,y,z;scanf("%d%d%d",&x,&y,&z);
    23             add(x,y,z);add(y,x,z);
    24             sum[x]+=z;sum[y]+=z;
    25         }
    26         for(int i=1;i<=m;i++){
    27             int u;scanf("%d",&u);
    28             if(u==0){
    29                 int x;scanf("%d",&x);
    30                 int ans=sum[x];
    31                 if(ans%2==1)printf("Girls win!
    ");
    32                 else printf("Boys win!
    ");
    33             }
    34             else {
    35                 int x,y,z;scanf("%d%d%d",&x,&y,&z);
    36                 for(int k=head[x];k;k=e[k].next){
    37                     int v=e[k].to;
    38                     if(v==y){
    39                         sum[x]-=e[k].value;
    40                         sum[x]+=z;
    41                         e[k].value=z;
    42                     }
    43                 }
    44                 for(int k=head[y];k;k=e[k].next){
    45                     int v=e[k].to;
    46                     if(v==x){
    47                         sum[y]-=e[k].value;
    48                         sum[y]+=z;
    49                         e[k].value=z;break;
    50                     }
    51                 }    
    52             }
    53         }
    54     }
    55     return 0;
    56 } 
  • 相关阅读:
    如何在Windows,Linux下查看JAVA端口占用情况(阿里)
    Java超类-java.lang.object
    多线程-Thread的run()与start()的区别
    sleep、yield、wait、join的区别(阿里)
    SOA (面向服务的架构)-Service Oriented Architecture
    MySQL存储过程详解 mysql 存储过程
    navicat创建存储过程的小问题
    SVN使用教程
    #pragma的用法
    windows下远程连接Mysql
  • 原文地址:https://www.cnblogs.com/DZN2004/p/12685483.html
Copyright © 2011-2022 走看看