#505. 「LibreOJ β Round」ZQC 的游戏

 

漂亮小姐姐点击就送:https://loj.ac/problem/505

 

输入格式

第一行一个正整数 T(1≤T≤100)T (1\le T \le 100)T(1T100),表示测试数据的组数。
对于每组测试数据,第一行两个正整数 n,m n, mn,m。
接下来 n nn 行,每行四个整数 x,y,w,r x, y, w, rx,y,w,r,其中第一个玩家是 ZQC。
接下来 m mm 行,每行三个整数 x,y,w x, y, wx,y,w。

输出格式

如果方案存在,输出一行 ZQC! ZQC!,否则输出一行 qaq

样例

样例输入

2
3 2
0 0 1 10
10 0 1 10
20 0 1 10
5 0 2
15 0 4
3 2
0 0 1 10
10 0 1 10
20 0 1 10
5 0 2
15 0 5

样例输出

ZQC! ZQC!
qaq


//一开始看成了有没有方案使得其他玩家的质量比zqc大
//但是其实是有没有方案使得没有其他玩家的质量比zqc大

//题目里的那个aij是 任意 非负整数 
//我们要让别人超不过zqc去,所以,让zqc把他能吃的都吃了
//别的人呢?
//我们不能让他们吃的比zqc重,
//也就是说,他们的初始质量加上他们增加的质量<=zqc的质量
//那么我们可以知道他们最多可以吃多少
//所以,源点向这些人连边,容量为他们最多能增加的重量 
//然后,让这些人向剩下的那些在他们范围内的食物球连边长为inf的边
//食物向汇点连他们质量的边
//这样,源点连出去的边是限制那些人增加的质量的,保证了他们的质量不会超过zqc
//那么,在这张图上跑最大流,会有两种情况: 
//        ①流量不等于所有食物的质量,也就是说在不超过zqc质量的限制下他们不能把食物吃完,
//          但是题目要求把食物吃完,所以他们的质量一定会有超过zcq的,那么zcq就输了
//        ②流量等于所有事物的质量,因为源点连向他们的边对他们有限制,所以他们把食物吃完了,而且质量还没超过zqc,那么zqc赢了


//本来建的图是把食物拆点,容量为他们的质量,然后第二个点向汇点连INF的边
//但是在lxt的指导下发现了不用这样,因为第二个点向汇点连的INF的边根本就不会流满,所以直接把食物连汇点就可以了 
//感谢lxt dalao 

//我靠坑啊
//谁都够不着的食物球不被吃
//但是我的方法没有把它减出来
//破题破题破题 妹的
//好吧其实是我太菜了
//mlgb 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

const int N=1e4+5;
const int M=1e5+5;
const int INF=0x7fffffff;

int n,m,S,T,Q;
int Flow,flow,Sum,P;
int head[N],num_edge;
struct Edge
{
    int v,flow,nxt;
}edge[M<<1];
struct XY
{
    int x,y,w,r;
    int flag;
}ply[N],food[N];

inline int read()
{
    char c=getchar();int num=0,f=1;
    for(;!isdigit(c);c=getchar())
        f=c=='-'?-1:f;
    for(;isdigit(c);c=getchar())
        num=num*10+c-'0';
    return num*f;
}

inline void add_edge(int u,int v,int flow)
{
    edge[++num_edge].v=v;
    edge[num_edge].flow=flow;
    edge[num_edge].nxt=head[u];
    head[u]=num_edge;
}

inline bool calc(int a,int i)    //计算距离,判断食物i在不在玩家a的范围内 
{
    return (food[i].x-ply[a].x)*(food[i].x-ply[a].x)+(food[i].y-ply[a].y)*(food[i].y-ply[a].y)<=ply[a].r*ply[a].r;
}

inline void count(int a)    //计算a可以吃多少食物 
{
    for(int i=1;i<=m;++i)
    {
        if(food[i].flag==1)        //这个球被zqc吃了 
            continue;
        if(calc(a,i))    //i在a的范围内 
        {
            add_edge(a,i+n,INF);    //连边 
            add_edge(i+n,a,0);
            food[i].flag=2;        //标记会被吃 
        }
    }
}

int dep[N];
inline bool bfs()    //板子 
{
    memset(dep,0,sizeof(dep));
    queue<int> que;
    dep[S]=1,que.push(S);
    int now,v;
    while(!que.empty())
    {
        now=que.front(),que.pop();
        for(int i=head[now];i;i=edge[i].nxt)
        {
            if(edge[i].flow)
            {
                v=edge[i].v;
                if(dep[v])
                    continue;
                dep[v]=dep[now]+1;
                if(v==T)
                    return 1;
                que.push(v);
            }
        }
    }
    return 0;
}

int dfs(int now,int flow)    //板子 
{
    if(now==T)
        return flow;
    int outflow=0,v,tmp;
    for(int i=head[now];i;i=edge[i].nxt)
    {
        if(edge[i].flow)
        {
            v=edge[i].v;
            if(dep[v]!=dep[now]+1)
                continue;
            tmp=dfs(v,min(flow,edge[i].flow));
            if(tmp)
            {
                outflow+=tmp;
                flow-=tmp;
                edge[i].flow-=tmp;
                edge[i^1].flow+=tmp;
                if(!flow)
                    return outflow;
            }
        }
    }
    dep[now]=0;
    return outflow;
}

int main()
{
    Q=read();
    while(Q--)
    {
        memset(head,0,sizeof(head));
        num_edge=1;
        n=read(),m=read();
        S=1,T=n+m+1;    //源汇点 
        for(int i=1;i<=n;++i)
        {
            ply[i].x=read(),
            ply[i].y=read(),
            ply[i].w=read(),
            ply[i].r=read();
        }
        Flow=0;        //剩下的人可吃的食物的总质量 
        for(int i=1;i<=m;++i)
        {
            food[i].flag=0;
            food[i].x=read(),
            food[i].y=read(),
            food[i].w=read();
            Flow+=food[i].w;    //加上 
        }
        Sum=ply[1].w;    //zqc的质量 
        for(int i=1;i<=m;++i)
        {
            if(calc(1,i))    //zqc可以吃第i个球 
            {
                Flow-=food[i].w;    //剩下的人可以吃的减少 
                Sum+=food[i].w;        //zqc长胖 
                food[i].flag=1;        //这个球被吃了 
            }
        }
        bool flag=0;
        for(int i=2;i<=n;++i)
        {
            if(Sum-ply[i].w<0)    //zqc把食物吃完了还是有比他重的,那他输了 
            {
                puts("qaq");
                flag=1;        //提前continue标记 
                break;
            }
            add_edge(S,i,Sum-ply[i].w),        //汇点向人连边连边,容量为他不超过zqc的情况下可以吃的最大的食物量 
            add_edge(i,S,0);
        }
        if(flag)
            continue;
        for(int i=2;i<=n;++i)    //人向食物连边 
            count(i);
        for(int i=1;i<=m;++i)
            if(!food[i].flag)    //谁也吃不到的食物要把它减出来 
                Flow-=food[i].w;
        for(int i=1;i<=m;++i)    //食物想汇点连边 
        {
            if(food[i].flag==1)        //被zqc吃掉的食物不连边 
                continue;
            add_edge(i+n,T,food[i].w);        //容量为食物质量 
            add_edge(T,i+n,0);
        }
        flow=0;
        while(bfs())
            flow+=dfs(S,INF);
        if(flow==Flow)        //judge
            puts("ZQC! ZQC!");
        else
            puts("qaq");
    }
    return 0;
}

 

 
posted @ 2018-03-24 08:34  whymhe  阅读(189)  评论(0编辑  收藏  举报