“浪潮杯”第九届山东省ACM大学生程序设计竞赛 B

GGO是一个以枪支和钢铁为主的世界,玩家为了成为最强壮的枪手而奋斗。 玩家Shino是一名狙击手,她的瞄准射击一次杀死一个怪物。 现在她在一张n * n地图上,并且有些网格中有怪物。 每个怪物都有经验。 不过,作为一名大师,史诺有一种奇怪的自我约束。 她最多会杀死一列中的一个怪物,而且最多也会杀死一个怪物。 现在,她想知道如何在尽可能多地杀死怪物的前提下获得最佳体验。
输入描述:

第一行包含一个整数n。
N <=500
然后n行。 在每一行中有n个
整数,Aij表示怪物在网格(i,j)的体验。
如果Aij = 0,则在网格(i,j)处没有怪物。
经验是所有被杀死的怪物的最低经验。
它保证怪物的最大体验不会超过109

输出描述:

一个整数,最大经验值。

题解:
最小值中的保证最大 明显二分
这题又是行列问题 ,二分图????不一定是,所以网络流跑一下

我们建立网络流就是寻找(在所有怪兽的能量大于某个值的限制条件下)能杀死的怪兽个数,二分能量值。杀死怪兽的最大个数是(怪兽的能量大于等于1我们就可以杀)的个数。

比赛的时候就想n皇后问题了。。。。。

代码如下:

#include<bits/stdc++.h>
using namespace std;
int a[600][600];
const int maxn=1200;
const int maxm=maxn*maxn;
int head[maxm],cnt=0;
const int inf=0x3f3f3f3f;
struct edge
{
    int v,nxt,w;
}edge[maxm*3+100];
void add_Edge(int u,int v,int w)
{
    edge[cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].nxt=head[u];
    head[u]=cnt++;
    edge[cnt].v=u;
    edge[cnt].w=0;
    edge[cnt].nxt=head[v];
    head[v]=cnt++;
}
int numh[maxn],h[maxn],curedge[maxn],pre[maxn];
int sap(int s,int t,int n)
{
    memset(numh,0,sizeof(numh));
    memset(h,0,sizeof(h));
    memset(pre,-1,sizeof(pre));
    int cur_flow,flow_ans=0,u,tmp,neck,i;
    for(i=1;i<=n;i++)
    {
        curedge[i]=head[i];
    }
    numh[0]=n;
    u=s;
    while(h[s]<n)
    {
        if(u==t)
        {
            cur_flow=inf;
            for(i=s;i!=t;i=edge[curedge[i]].v)
            {
                if(cur_flow>edge[curedge[i]].w)
                {
                    neck=i;
                    cur_flow=edge[curedge[i]].w;
                }
            }
            for(i=s;i!=t;i=edge[curedge[i]].v)
            {
                tmp=curedge[i];
                edge[tmp].w-=cur_flow;
                edge[tmp^1].w+=cur_flow;
            }
            flow_ans+=cur_flow;
            u=neck;
        }
        for(i=curedge[u];i!=-1;i=edge[i].nxt)
        {
            if(edge[i].w&&h[u]==h[edge[i].v]+1)
            {
                break;
            }
        }
        if(i!=-1)
        {
            curedge[u]=i;
            pre[edge[i].v]=u;
            u=edge[i].v;
        }
        else
        {
            if(0==--numh[h[u]])
                break;
            curedge[u]=head[u];
            for(tmp=n,i=head[u];i!=-1;i=edge[i].nxt)
            {
                if(edge[i].w)
                {
                    tmp=min(tmp,h[edge[i].v]);
                }
            }
            h[u]=tmp+1;
            ++numh[h[u]];
            if(u!=s)
                u=pre[u];
        }
    }
    return flow_ans;
}
int solve(int limit,int s,int t,int n)
{
    memset(head,-1,sizeof(head));
    cnt=0;
    //printf("111111");
    for(int i=1;i<=n;i++)
    {
        add_Edge(s,i,1);
        add_Edge(i+n,t,1);
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            //printf("%d ",a[i][j]);
            if(a[i][j]>=limit)
            {
                add_Edge(i,j+n,1);
                //printf("%d %d\n",i,j+n);
            }
        }
    }
    /*for(int i=1;i<=t;i++)
    {
        for(int j=head[i];j!=-1;j=edge[j].nxt)
        {
            int v=edge[j].v;
            printf("%d %d\n",i,v);
        }
    }*/
    int answer=sap(s,t,t);
    //printf("%d\n",answer);
    return answer;
}
int main ()
{
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            scanf("%d",&a[i][j]);
        }   
    }
    int s=n*2+1;
    int t=n*2+2;
    int answer=solve(1,s,t,n);
    //printf("%d\n",answer);
    int l=1,r=1000000000;
    int ans=1;
    while(l<=r)
    {
        int mid=(r-l)/2+l;  
        int midd=solve(mid,s,t,n);
        if(midd>=answer)
        {
            l=mid+1;
            ans=mid;
        }
        else
        {
            r=mid-1;
        }
    }
    printf("%d\n",ans);
    }
} 

猜你喜欢

转载自blog.csdn.net/qq_36616023/article/details/80573914