zoukankan      html  css  js  c++  java
  • #505. 「LibreOJ β Round」ZQC 的游戏

     

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

    输入格式

    第一行一个正整数 T(1≤T≤100)T (1le 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;
    }
     
  • 相关阅读:
    whereis which type find
    souce and bash 的区别
    systemctl daemon-reload
    linux /etc/profile bashrc bash_profile
    ulimt 和 sysctl
    MySQL 问题总结
    asyncio
    Linux 中 MySQL 操作
    总结一波 Redis 面试题
    os 模块 和 re 模块
  • 原文地址:https://www.cnblogs.com/lovewhy/p/8636455.html
Copyright © 2011-2022 走看看