zoukankan      html  css  js  c++  java
  • POJ3680 Intervals(最小费用最大流)

    选择若干条线段使权值最大,并且点覆盖次数不超过k。

    建图如下:vs到0建立容量为k费用为0的边;坐标终点到vt连接一条容量为k费用为0的边;对于每两个相邻坐标连接一条容量为INF费用为0的边;对于线段每两个端点连接一条容量1费用为-cost的边。

    这样跑最小费用最大流。相当于找出k个线段集合,每个集合的线段都不重合。原问题就这样求解。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<queue>
     4 #include<algorithm>
     5 using namespace std;
     6 #define INF (1<<30)
     7 #define MAXN 444 
     8 #define MAXM 444*444*2 
     9 struct Edge{
    10     int u,v,cap,cost,next;
    11 }edge[MAXM];
    12 int head[MAXN];
    13 int NV,NE,vs,vt;
    14 
    15 void addEdge(int u,int v,int cap,int cost){
    16     edge[NE].u=u; edge[NE].v=v; edge[NE].cap=cap; edge[NE].cost=cost;
    17     edge[NE].next=head[u]; head[u]=NE++;
    18     edge[NE].u=v; edge[NE].v=u; edge[NE].cap=0; edge[NE].cost=-cost;
    19     edge[NE].next=head[v]; head[v]=NE++;
    20 }
    21 bool vis[MAXN];
    22 int d[MAXN],pre[MAXN];
    23 bool SPFA(){
    24     for(int i=0;i<NV;++i){
    25         vis[i]=0;
    26         d[i]=INF;
    27     }
    28     vis[vs]=1;
    29     d[vs]=0;
    30     queue<int> que;
    31     que.push(vs);
    32     while(!que.empty()){
    33         int u=que.front(); que.pop();
    34         for(int i=head[u]; i!=-1; i=edge[i].next){
    35             int v=edge[i].v;
    36             if(edge[i].cap && d[v]>d[u]+edge[i].cost){
    37                 d[v]=d[u]+edge[i].cost;
    38                 pre[v]=i;
    39                 if(!vis[v]){
    40                     vis[v]=1;
    41                     que.push(v);
    42                 }
    43             }
    44         }
    45         vis[u]=0;
    46     }
    47     return d[vt]!=INF;
    48 }
    49 int MCMF(){
    50     int res=0;
    51     while(SPFA()){
    52         int flow=INF,cost=0;
    53         for(int u=vt; u!=vs; u=edge[pre[u]].u){
    54             flow=min(flow,edge[pre[u]].cap);
    55         }
    56         for(int u=vt; u!=vs; u=edge[pre[u]].u){
    57             edge[pre[u]].cap-=flow;
    58             edge[pre[u]^1].cap+=flow;
    59             cost+=flow*edge[pre[u]].cost;
    60         }
    61         res+=cost;
    62     }
    63     return res;
    64 }
    65 
    66 int from[222],to[222],cost[222];
    67 int point[444],pn;
    68 int main(){
    69     int t,n,k;
    70     scanf("%d",&t);
    71     while(t--){
    72         scanf("%d%d",&n,&k);
    73         pn=0;
    74         for(int i=0; i<n; ++i){
    75             scanf("%d%d%d",from+i,to+i,cost+i);
    76             point[pn++]=from[i]; point[pn++]=to[i];
    77         }
    78         sort(point,point+pn);
    79         pn=unique(point,point+pn)-point;
    80 
    81         vs=pn; vt=vs+1; NV=vt+1; NE=0;
    82         memset(head,-1,sizeof(head));
    83 
    84         addEdge(vs,0,k,0);
    85         addEdge(pn-1,vt,k,0);
    86         for(int i=1; i<pn; ++i){
    87             addEdge(i-1,i,INF,0);
    88         }
    89         for(int i=0; i<n; ++i){
    90             int x=lower_bound(point,point+pn,from[i])-point;
    91             int y=lower_bound(point,point+pn,to[i])-point;
    92             addEdge(x,y,1,-cost[i]);
    93         }
    94 
    95         printf("%d
    ",-MCMF());
    96     }
    97     return 0;
    98 }
  • 相关阅读:
    HDU2034 人见人爱 A
    二分查找
    利用向量积(叉积)计算三角形(多边形)的面积
    找出能被5或6整除,但是不能被两者同时整除的数 Exercise05_11
    找出分数最高的前两个学生 Exercise05_09
    金融应用,计算将来的学费 Exercise05_07
    千克与磅之间的转换 Exercise05_05
    将千克转换成磅 Exercise05_03
    统计正数和负数的个数,然后计算这些数的平均值 Exercise05_01
    回文数
  • 原文地址:https://www.cnblogs.com/WABoss/p/4853531.html
Copyright © 2011-2022 走看看