HDU-2413 Against Mammoths(二分答案+最大匹配)

题意

人类掌握了 n 1 个星球,外星人掌握了 n 2 个星球。第 i 星球每年将生产 a i 艘军舰。 每个人类星球只会经过一个外星球,一个外星球也只会被一个人类星球进攻。人类星球 i 到外星球 j 需花费 e i , j 时间。如果人类星球的军舰数大于等于外星球的军舰数,就能占领这个星球。 求最少多少年后就能占领所有的外星球。
1 n 1 , n 2 250

思路

这种模型题首先应该建立二分图。此题还是比较明显的,对地球人的星球和外星人的星球分别建立一个集合。如果地球人能攻下外星人的星球,那么就连一条边。不难看出越久占领的可能性越大(注意人类可以在规定时间前任意时间点发动进攻),于是二分规定时间。现在只用判断,人类星球在某一时间前能否攻下外星人星球即可。我的方法是预处理人类星球 i 打下外星球 j 的最早时间,然后判断这个时间是否小于规定时间。

代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define FOR(i,x,y) for(int i=(x);i<=(y);i++)
#define DOR(i,x,y) for(int i=(x);i>=(y);i--)
#define N 253
typedef long long LL;
using namespace std;
template<const int maxn,const int maxm>struct Linked_list
{
    int head[maxn],to[maxm],nxt[maxm],tot;
    void clear(){memset(head,-1,sizeof(head));tot=0;}
    void add(int u,int v){to[++tot]=v,nxt[tot]=head[u],head[u]=tot;}
    #define EOR(i,G,u) for(int i=G.head[u];~i;i=G.nxt[i])
};
Linked_list<N,N*N>G;
int a[N],ka[N],b[N],kb[N],e[N][N],lb[N][N];
int mc[N],mark[N],n1,n2;

int updiv(int a,int b){return (a+b-1)/b;}
void simulation()
{
    FOR(i,1,n1)
        FOR(j,1,n2)
        {
            if(a[i]-ka[i]*e[i][j]>=b[j])lb[i][j]=0;
            else if(ka[i]<=kb[j])lb[i][j]=2e9+1e8;
            else lb[i][j]=updiv(b[j]-a[i]+ka[i]*e[i][j],ka[i]-kb[j]);
        }
}
bool match(int u,int stmp)
{
    EOR(i,G,u)
    {
        int v=G.to[i];
        if(mark[v]==stmp)continue;
        mark[v]=stmp;
        if(!mc[v]||match(mc[v],stmp))
        {
            mc[v]=u;
            return true;
        }
    }
    return false;
}
bool check(int k)
{
    G.clear();
    FOR(i,1,n1)FOR(j,1,n2)if(k>=lb[i][j])G.add(i,j);
    int ans=0;
    memset(mark,0,sizeof(mark));
    memset(mc,0,sizeof(mc));
    FOR(i,1,n1)if(match(i,i))ans++;
    return ans==n2;
}

int main()
{
    while(scanf("%d%d",&n1,&n2),n1||n2)
    {
        FOR(i,1,n1)scanf("%d%d",&a[i],&ka[i]);
        FOR(i,1,n2)scanf("%d%d",&b[i],&kb[i]);
        FOR(i,1,n1)FOR(j,1,n2)scanf("%d",&e[i][j]);
        simulation();
        int L=0,R=1e9+10;
        while(L<R)
        {
            int mid=L+R>>1;
            if(check(mid))
                R=mid;
            else L=mid+1;
        }
        if(L>1e9)printf("IMPOSSIBLE\n");
        else printf("%d\n",L);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Paulliant/article/details/81565037