Destroying The Graph(poj 2125)

题意:

给你一张有向图,你可以选择一个点:
• 摧毁其所有的入边,代价A[i].
• 摧毁其所有的出边,代价B[i].
• 求摧毁这张图的最小代价。
• 数据范围1000

/*
  很经典的一道题目(我这么弱,稍微一变形就不会了)
  因为每个点涉及到出边和入边,所以可以考虑拆点,然后建图,接下来就成了一个最小点权覆盖的问题。
  最小点权覆盖就是求最小割(证明可参考胡伯涛论文“最小割模型在信息学竞赛中的应用”)。
  接下来是输出方案,因为我们要选择的点与S或T连得边是满流的,所以可以dfs一边,只走不满流的,
  那么如果一个<=n的点走不到,说明它被选择了(这个很好理解),如果一个>n的点能走到,说明它被选择了, 
  这是因为如果这个点没有被选择,说明从前面水流流过来的时候到某个位置已经割断了,在这里就没必要再割了。 
  (貌似好难理解的样子,我这么弱肯定想不出来)。 
*/
#include<cstdio>
#include<iostream>
#define N 210
#define M 5010
#define inf 1000000000
using namespace std;
int a[N],b[N],head[N],dis[N],q[N],vis[N],n,m,cnt=1,S,T;
struct node{
    int v,f,pre;
};node e[M*2];
void add(int u,int v,int f){
    e[++cnt].v=v;e[cnt].f=f;e[cnt].pre=head[u];head[u]=cnt;
    e[++cnt].v=u;e[cnt].f=0;e[cnt].pre=head[v];head[v]=cnt;
}
bool bfs(){
    for(int i=1;i<=T;i++)dis[i]=inf;
    int h=0,t=1;q[1]=S;dis[S]=0;
    while(h<t){
        int u=q[++h];
        for(int i=head[u];i;i=e[i].pre){
            int v=e[i].v;
            if(e[i].f&&dis[u]+1<dis[v]){
                dis[v]=dis[u]+1;
                if(v==T)return true;
                q[++t]=v;
            }
        }
    }
    if(dis[T]==inf)return false;
    return true;
}
int dinic(int now,int f){
    if(now==T)return f;
    int rest=f;
    for(int i=head[now];i;i=e[i].pre){
        int v=e[i].v;
        if(e[i].f&&dis[v]==dis[now]+1){
            int t=dinic(v,min(rest,e[i].f));
            if(!t)dis[v]=0;
            e[i].f-=t;
            e[i^1].f+=t;
            rest-=t;
        }
    }
    return f-rest;
}
void dfs(int x){
    vis[x]=1;
    for(int i=head[x];i;i=e[i].pre){
        if(!e[i].f||vis[e[i].v])continue;
        dfs(e[i].v);
    }
}
int main(){
    scanf("%d%d",&n,&m);
    S=0,T=2*n+1;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        add(i+n,T,a[i]);
    }
    for(int i=1;i<=n;i++){
        scanf("%d",&b[i]);
        add(S,i,b[i]);
    }
    for(int i=1;i<=m;i++){
        int x,y;scanf("%d%d",&x,&y);
        add(x,y+n,inf);
    }
    int min_cnt=0,p=0,pin=0,pout=0;
    while(bfs()) min_cnt+=dinic(S,inf);
    printf("%d\n",min_cnt);
    dfs(S);
    for(int i=1;i<=n;i++){
        if(!vis[i])p++;
        if(vis[i+n])p++;
    }
    printf("%d\n",p);
    for(int i=1;i<=n;i++){
        if(!vis[i])printf("%d -\n",i);
        if(vis[i+n])printf("%d +\n",i);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/harden/p/6257816.html

Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值