jzoj1350-游戏(某C组)【SPFA,图,最短路】

本文介绍了一款基于树形结构的博弈游戏算法实现。通过SPFA算法计算从每个节点到树根的最短路径,并根据玩家Alice和Bob各自的石头位置进行胜负判断,最终确定胜者。

前言

每天一道C组题get√

题目

有一颗树,只有一个树根,Alice有M1块石头,Bob有M2块石头,Alice先移每个人轮流移动石头,谁先把自己的石头全部移动到树根处就失败了,输出游戏胜者。


Input

  输入包含多组测试数据。
  第一行输入T(T<=10)表示测试数据组数。
  接下来每组测试数据第一行输入3个整数N(1<=N<=10000),M1(1<=M1<=10000),M2(1<=M2<=10000),其中N表示树的节点数。
  接下来N-1行描述树,每行包含两个整数A和B(0<=A,B<=N-1)表示树中有一条边连接A,B两点,注意0是树根。
  接下来一行M1个数,表示Alice的M1个石子的位置。
  接下来一行M2个数,表示Bob的M2个石子的位置。

Output

对于每组测试数据,输出赢家的名字。

Sample Input

2
3 1 1
0 1
2 0
1
2
3 2 1
0 1
1 2
2 2
2

Sample Output

Bob
Alice


解题思路

用SPFA求出每个点到根节点的最短路,然后加以判断


代码

#include<cstdio>
#include<cstring>
using namespace std;
struct line{
    int last,next;
}a[20001];
int f[10002],ls[10002],state[10002],t,n,m1,m2,dx,dy,w;
int head,tail,s;
bool b[10002];
void spfa()//找最短路
{
    memset(f,127/3,sizeof(f));
    head=0;tail=1;
    state[1]=1;b[1]=true;int q;f[1]=0;
    do
    {
        head=(head+2)%(n+1)-1;
        q=ls[state[head]];
        while (q!=0)
        {
            if (f[state[head]]+1<f[a[q].last])
            {
                f[a[q].last]=f[state[head]]+1;
                if (!b[a[q].last])
                {
                    b[a[q].last]=true;
                    tail=(tail+2)%(n+1)-1;
                    state[tail]=a[q].last;
                }
            }
            q=a[q].next;
        }
        b[state[head]]=false;
    }
    while (head!=tail);
}
int main()
{
    scanf("%d",&t);
    for (int ti=1;ti<=t;ti++)
    {
        memset(ls,0,sizeof(ls));
        scanf("%d%d%d",&n,&m1,&m2);
        w=0;
        for (int i=1;i<n;i++)
        {
            scanf("%d%d",&dy,&dx);
            a[++w].last=dy+1;
            a[w].next=ls[dx+1];
            ls[dx+1]=w;
            a[++w].last=dx+1;
            a[w].next=ls[dy+1];
            ls[dy+1]=w;//建图
        }
        spfa();s=0;
        for (int i=1;i<=m1;i++)
        {
            scanf("%d",&dx);
            s+=f[dx+1];//累计
        }
        for (int i=1;i<=m2;i++)
        {
            scanf("%d",&dx);
            s-=f[dx+1];//累计
        }       
        if (s>0) printf("Alice\n");
        else printf("Bob\n");//判断输赢
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值