poj 3308 Paratroopers

这是一个关于利用最小割算法解决矩阵问题的博客。题目要求在矩阵中消灭所有敌人,通过放置炮弹在行或列上,找到最小花费的解决方案。博主使用了SAP(匈牙利算法)来构建网络流模型,建立超级源点、超级汇点,通过加边和最小割计算得出最小成本。
摘要由CSDN通过智能技术生成
题意:在一个矩阵中某些坐标点存在你的敌人,现有一些炮弹,他们可以摆在任意一行或者任意一列,并且可以消灭掉一行或者一列上的敌人。要求消灭掉所都敌人需要的最小花费。

最小点覆盖:
建立超级源点和每行连接,权值为放在该行炮弹的花费。
建立超级汇点和每列连接,权值为放在该列炮弹的花费。
存在敌人的行和列之间连一条边,权值为inf。
跑一遍最小割。


#include<cmath>
#include<stdio.h>
#include<string.h>
#include<iostream>
#define inf 10000000
using namespace std;
struct node{
int u,v,next;
double c;
}edge[1200];
int head[1200],pre[1200],cur[1200],dis[1200],gap[1200];
double flow[1200],a[1200],b[1200];
int T,m,n,l,x,y,e,start,end;
double ans,tot;

void add_adge(int u,int v,double c)
{
    edge[e].u=u;  edge[e].v=v;  edge[e].c=c;  edge[e].next=head[u]; head[u]=e++;
    edge[e].u=v;  edge[e].v=u;  edge[e].c=0;  edge[e].next=head[v]; head[v]=e++;
}

double sap()  
{   
    double flow=0,aug=inf;  
    bool flag; int u;
    for(int i=0; i<=n+m+1; i++)  
    {  
        cur[i]=head[i];  
        gap[i]=dis[i]=0;  
    }  
    gap[start]=n+m+2;   
    u=pre[start]=start; 
    while(dis[start]<n+m+2)  
    {  
        flag=0;  
        for(int &j=cur[u]; j!=-1; j=edge[j].next)  
        {  
            int v=edge[j].v;  
            if(edge[j].c>0&&dis[u]==dis[v]+1)  
            {  
                flag=1;  
                if(edge[j].c<aug) aug=edge[j].c;  
                pre[v]=u;  
                u=v;  
                if(u==n+m+1)  
                {  
                    flow+=aug;  
                    while(u!=0)  
                    {  
                        u=pre[u];  
                        edge[cur[u]].c-=aug;  
                        edge[cur[u]^1].c+=aug;  
                    }  
                    aug=inf;  
                }  
                break;  
            }  
        } 
        if(flag) continue;  
        int mindis=n+m+2;  
        for(int j=head[u]; j!=-1; j=edge[j].next)  
        {  
            int v=edge[j].v;  
            if(edge[j].c>0&&dis[v]<mindis)  
            {  
                mindis=dis[v];  
                cur[u]=j;  
            }  
        }  
        if((--gap[dis[u]])==0)  
            break;  
        gap[dis[u]=mindis+1]++;  
        u=pre[u];  
    }  
    return flow;  
}  



int main()
{
    scanf("%d",&T);
    while(T--)
    {
       scanf("%d%d%d",&m,&n,&l);
       e=0;start=0,end=n+m+1;
       memset(head,-1,sizeof(head));
       for(int i=1;i<=m;i++)
       {
          scanf("%lf",&a[i]);
          add_adge(0,i,log(a[i]));
       }
       for(int i=1;i<=n;i++)
       { 
          scanf("%lf",&b[i]);
          add_adge(m+i,m+n+1,log(b[i]));
       }
       for(int i=1;i<=l;i++)
       {
          scanf("%d%d",&x,&y);
          add_adge(x,m+y,inf);
       }
       printf("%.4lf\n",exp(sap())); 
    } 
    return 0;
} 

       

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值