poj 3680 (費用流拆點+離散+神奇的構圖)

題目:給定N個區間(ai,bi)權值wi,選一些區間,求最大權和且每個點最多覆蓋K次

做法是 先把所有的區間離散化 ,也就是隻留端點,然後排序,去重,標號。 
增加超級源超級匯s,t.
假設剩下n個點, 加上超級源超級匯是n+2個。超級源爲0,匯爲n+1.
從0開始,順序建一條流量爲k,費用爲0的邊,將所有點串起來。然後再根據所輸入邊的信息,找到對應點的位置,連一條流量是1,費用是-w的邊,最後從s到t做最小費用。

比如說 
3 1
1 3 2
2 3 4
3 4 8

將 1,3,2,3,3,4排序
變成 1 2 3 3 3 4
去重 1 2 3 4
然後 0->1 1->2 2->3 3->4 4->5 建邊
再 1->3 2->3 3->4 建邊 即可


#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<cmath>
#include<cstdlib>
#include<stack>
#include<queue>
#include <iomanip>
#include<iostream>
#include<algorithm>
using namespace std ;
const int N=1000 ;
const int M=5000 ;
const int inf=1<<30 ;
struct node
{
	int u ,v,c,cost,next ;
}edge[M];

struct node1
{
	int x,y,w;
}e[N] ;

int head[N],pp[N],pre[N],vist[N],dist[N] ,a[N];
int top ;

  
void add(int u ,int v,int c,int cost)        
{        
    edge[top].u=u;        
    edge[top].v=v;        
    edge[top].c=c;        
    edge[top].cost=cost;        
    edge[top].next=head[u];        
    head[u]=top++;        
    edge[top].u=v;        
    edge[top].v=u;        
    edge[top].c=0;        
    edge[top].cost=-cost;        
    edge[top].next=head[v];        
    head[v]=top++;        
}        
        
int SPFA(int s,int t)        
{        
    int u , v ;        
    memset(vist,0,sizeof(vist));        
    memset(pre,-1,sizeof(pre));        
    for(int i = 0 ; i <= t ; i++)  dist[i]=inf ;        
    vist[s]=1;dist[s]=0;pre[s]=s;        
    queue<int>q;        
    q.push(s);        
    while(!q.empty())        
    {        
         u=q.front();        
         q.pop();        
         vist[u]=0;        
         for(int i =head[u];i!=-1;i=edge[i].next)        
         {        
               v=edge[i].v;        
               if(edge[i].c && dist[v] > dist[u]+edge[i].cost)        
               {        
                    dist[v] = dist[u]+edge[i].cost ;        
                     pre[v]=u;        
                     pp[v]=i;        
                     if(!vist[v]);        
                     {        
                           vist[v]=1;        
                           q.push(v);        
                     }        
               }        
        }        
    }        
    if(dist[t]==inf) return 0;        
    return 1 ;        
}        
        
int MFMC(int s,int t)        
{        
    int mincost=0,flow=0,minflow ;        
    while(SPFA(s,t))        
    {        
          minflow=inf;        
          for(int i=t;i!=s;i=pre[i])        
              minflow=min(minflow,edge[pp[i]].c);        
          for(int i=t;i!=s;i=pre[i])        
          {        
                edge[pp[i]].c -= minflow;        
                edge[pp[i]^1].c += minflow;        
          }            
          flow += minflow;        
          mincost += dist[t]*minflow ;        
        //  printf("****");    
    }        
    return -mincost ;        
}        
  

int main()
{
	int T,n,k,cnt ;
	scanf("%d",&T);
	while(T--)
	{
		   top = 0; cnt=0;
	       memset(head,-1,sizeof(head)) ;
	       memset(a,0,sizeof(a)) ;
	       scanf("%d%d",&n,&k);
	       for(int i = 0 ; i < n ; i++)
	       {
	       	    scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w) ;
	       	    a[cnt++]=e[i].x ; a[cnt++]=e[i].y ;
	       }
		   sort(a,a+cnt) ;
		   int tmp = 1 ;
		   for(int i = 1 ; i < cnt ; i++)
		   {
		   	    if(a[i]!=a[i-1]) 				  
				      a[tmp++]=a[i];			  
		   }
		   for(int  i = 1 ; i < tmp ; i++)
		   {
		   	    add(i,i+1,k,0) ;
		   }
		   for(int i = 0 ; i < n ;i++)
		   {         //返回大於或等於e[i].x的第一個元素下標位置
		   	       int u = lower_bound(a,a+tmp,e[i].x)-a;
                   int v = lower_bound(a,a+tmp,e[i].y)-a; 
                   add(u+1,v+1,1,-e[i].w) ;  //數組a從0開始 ,所以要加1,0號留給 S ; 
		   }
		   int s = 0 ,t = tmp+1 ;
		   add(s,1,k,0);
		   add(tmp,t,k,0) ;
		   int ans = MFMC(s,t) ; 
		  printf("%d\n",ans);
	}
	return 0; 
}
	 
	 


發佈了218 篇原創文章 · 獲贊 5 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章