[SDOI2015] 星际战争 题解

假如将所有激光武器放在一边,所有机器人放在一边,激光武器向它可以伤害的机器人连边,再加超级源/汇点,这就是一个网络流问题。

考虑激光武器向机器人连的边容量无限,而机器人向超级汇点连的边容量为机器人的装甲值,而超级源点连向激光武器的边则是用时 \(\times\) 激光武器伤害。

发现假如答案为 \(ans\),则所有大于 \(ans\) 的情况都可以击溃所有机器人,而用时小于 \(ans\) 则一定无法击溃所有机器人,发现单调性,二分用时,看最大流是否等于机器人装甲值之和。

时间复杂度 \(O((n+m)^2nm\log maxans)\),其中 \(maxans\) 是答案上界。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=105,M=5505;
int n,m,s,t,h[N],d[N],c[N];
int k,to[M],nxt[M],e[N][N];
int w[M],a[N],b[N],sum;
void add(int x,int y,int z){
    w[++k]=z;to[k]=y;
    nxt[k]=h[x];h[x]=k;
    nxt[++k]=h[y];
    to[k]=x;h[y]=k;
}int bfs(){
    memset(c,-1,sizeof(c));
    queue<int>q;q.push(s);
    c[s]=0;d[s]=h[s];
    while(q.size()){
        int x=q.front();q.pop();
        for(int i=h[x];i;i=nxt[i]){
            int y=to[i],lv=w[i];
            if(lv>0&&c[y]==-1)
                d[y]=h[y],c[y]=c[x]+1,q.push(y);
        }
    }return (c[t]==-1)?0:1;
}int dfs(int x,int ans){
    if(x==t) return ans;
    int now=ans;
    for(int i=h[x];i&&now;i=nxt[i]){
        int y=to[i];int lv=w[i];
        if(lv<1||c[y]!=c[x]+1) continue;
        int zjy=dfs(y,min(now,lv));
        now-=zjy;w[i]-=zjy;w[i^1]+=zjy;
    }return ans-now;
}int dinic(){
    int ans=0;
    while(bfs())
        ans+=dfs(s,1e18);
    return ans;
}int check(int x){
    memset(h,0,sizeof(h));
    memset(to,0,sizeof(to));
    memset(w,0,sizeof(w));k=1;
    memset(nxt,0,sizeof(nxt));
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            if(e[i][j]) add(i+n,j,1e18);
    for(int i=1;i<=n;i++)
        add(i,t,a[i]);
    for(int i=1;i<=m;i++)
        add(s,i+n,b[i]*x);
    if(dinic()==sum) return 1;
    return 0;
}signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    cin>>n>>m;t=n+m+1;
    for(int i=1;i<=n;i++)
        cin>>a[i],a[i]*=10000,sum+=a[i];
    for(int i=1;i<=m;i++) cin>>b[i];
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            cin>>e[i][j];
    int l=0,r=200000000,ans;
    while(l<=r){
        int mid=(l+r)/2;
        if(check(mid))
            ans=mid,r=mid-1;
        else l=mid+1;
    }printf("%.6lf",ans/1e4);
    return 0;
}
posted @ 2024-05-05 14:44  长安一片月_22  阅读(10)  评论(0编辑  收藏  举报