题意
人类掌握了
n1
n
1
个星球,外星人掌握了
n2
n
2
个星球。第
i
i
星球每年将生产 艘军舰。 每个人类星球只会经过一个外星球,一个外星球也只会被一个人类星球进攻。人类星球
i
i
到外星球 需花费
ei,j
e
i
,
j
时间。如果人类星球的军舰数大于等于外星球的军舰数,就能占领这个星球。 求最少多少年后就能占领所有的外星球。
1≤n1,n2≤250
1
≤
n
1
,
n
2
≤
250
思路
这种模型题首先应该建立二分图。此题还是比较明显的,对地球人的星球和外星人的星球分别建立一个集合。如果地球人能攻下外星人的星球,那么就连一条边。不难看出越久占领的可能性越大(注意人类可以在规定时间前任意时间点发动进攻),于是二分规定时间。现在只用判断,人类星球在某一时间前能否攻下外星人星球即可。我的方法是预处理人类星球 i i 打下外星球 的最早时间,然后判断这个时间是否小于规定时间。
代码
#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;
}