POJ 3343 Against Mammoths(二分匹配+二分答案)
题意:(这个题目好长~~~)有n个人类星球,m个外星球,每个星球上开始sh艘飞船,之后每年会生产p艘飞船,人类想要战胜所有的外星球,每个人类星球和每个外星球的距离已知(需要耗费k年),比如在a年初,人类星球H向外星球A宣战,那么人类会带上sh+p*a艘飞船进攻,经过k年后到达外星球,这时外星球飞船的数量为sh'+p'*(a+k),如果这时人类飞船的数量>=外星球飞船的数量,那么就会战胜这个外星球,每个人类星球只能攻击一个外星球,一个外星球只能被一个人类星球攻击,问最少需要多少年人类才能全部战胜所有的外星球。
思路:由于人类星球和外星球是一一对应的关系,所以自然想到了二分匹配,但是时间是未知的,所以可以通过二分答案的途径来确定时间,对于每个时间k检测人类是否能打败所有的外星球.....输出最小值就可以了,由于答案是从1<<31-1开始二分的,所以计算过程中可能会超出int范围,故要注意__int64类型的转换。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <memory.h>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
using namespace std;
const int BORDER = (1<<26)-1;
const int MAXSIZE = 37;
const int MAXN = 300;
const int INF = 0x6ffffff;
#define CLR(x,y) memset(x,y,sizeof(x))
#define ADD(x) x=((x+1)&BORDER)
#define IN(x) scanf("%d",&x)
#define OUT(x) printf("%d\n",x)
#define MIN(m,v) (m)<(v)?(m):(v)
#define MAX(m,v) (m)>(v)?(m):(v)
#define ABS(x) ((x)>0?(x):-(x))
typedef struct{
int v,next;
int val;
}Edge;
typedef struct{
int sh;
int p;
}Node;
int n,m,ans,index;
int dist[MAXN][MAXN],net[MAXN],pre[MAXN];
bool visit[MAXN];
Edge edge[MAXN*MAXN];
Node hum[MAXN],mam[MAXN];
void add_edge(const int& u,const int& v)
{
edge[index].v = v;
edge[index].next = net[u];
net[u] = index;
++index;
}
bool _check(const Node& a,const Node& b,const int& dis,const int& limit)
{
if(limit < dis)
return false;
if(a.sh >= b.sh+(__int64)dis*b.p)
return true;
if(a.sh+(__int64)(limit-dis)*a.p >= b.sh+(__int64)limit*b.p)
return true;
return false;
}
int init()
{
index = 0;
ans = -1;
CLR(net,-1);
CLR(pre,-1);
return 0;
}
int input()
{
int i,j,a,b,val;
for(i = 0; i < n; ++i)
scanf("%d%d",&hum[i].sh,&hum[i].p);
for(i = 0; i < m; ++i)
scanf("%d%d",&mam[i].sh,&mam[i].p);
for(i = 0; i < n; ++i)
for(j = 0; j < m; ++j)
{
scanf("%d",&dist[i][j]);
}
return 0;
}
bool dfs(const int& u)
{
int i,v;
for(i = net[u]; i != -1; i = edge[i].next)
{
v = edge[i].v;
if(!visit[v])
{
visit[v] = true;
if(pre[v] == -1 || dfs(pre[v]))
{
pre[v] = u;
return true;
}
}
}
return false;
}
int make_graph(const __int64& limit)
{
int i,j,val,u,v,tmp;
index = 0;
CLR(net,-1);
CLR(pre,-1);
for(i = 0; i < n; ++i)
for(j = 0; j < m; ++j)
{
if(_check(hum[i],mam[j],dist[i][j],limit))
add_edge(i,j);
}
return 0;
}
int work()
{
int i,j,tmp;
__int64 b_low = 0;
__int64 b_high = (1<<31)-1;
__int64 b_mid;
while(b_low <= b_high)
{
b_mid = (__int64)(b_low+b_high)>>1;
make_graph(b_mid);
tmp = 0;
for(i = 0; i < n; ++i)
{
CLR(visit,0);
if(dfs(i))
++tmp;
}
if(tmp == m)
{
ans = b_mid;
b_high = b_mid - 1;
}
else
b_low = b_mid + 1;
}
if(ans == -1)
printf("IMPOSSIBLE\n");
else
OUT(ans);
return 0;
}
int main()
{
while(scanf("%d%d",&n,&m))
{
if(!n && !m)
break;
init();
input();
work();
}
return 0;
}