poj 3680 最小费用流

来源:互联网 发布:c语言字符串函数 编辑:程序博客网 时间:2024/06/13 12:28

题意:n个区间,每个区间都有权值,尽可能的去取区间,但要保证每个点不被取超过k次。

题解:

主要就是建图:我是不会建。。我太笨了。

首先,我们不可能每个点使其都存在。太多了。所以我们就取每个区间的端点。这样,每个端点之间的流量为k,费用为权值。但是,为了确保我们不想取这个区间时有别的选择,就把所有的点从小到大 连起来,流量为k,为用为0。这样当我们不想取某个区间时,就从费用为零的边上流过就行了。

另:要把端点离散化,排序,重编号。

#include<stdio.h>#include<algorithm>#include<string.h>#define MX 10000000#define nMax 500#define eMax 10000using namespace std;struct Egde{int u,v,c,w,next,pre; }eg[eMax];int n, m, ans,vs,vt,cas,K;int k, list[nMax];int que[nMax], pre[nMax], dis[nMax];struct interval{int x,y,w;}inl[210];int hash[100010];bool vis[nMax];void add(int u, int v, int c, int w){eg[k].u=u;eg[k].v=v;eg[k].pre=k+1;eg[k].next=list[u];eg[k].c=c;eg[k].w=w;list[u]=k++;eg[k].u=v;eg[k].v=u;eg[k].pre=k-1;eg[k].next=list[v];eg[k].c=0;eg[k].w=-w;list[v]=k++;}bool spfa(){                 int i, head = 0, tail = 1;for(i = vs; i <= vt; i ++){dis[i] = MX;vis[i] = false;}dis[vs] = 0;que[0] = vs;vis[vs] = true;while(tail != head){ int u = que[head ++];for(i = list[u]; i != -1; i = eg[i].next){int v = eg[i].v;if(eg[i].c&& dis[v] > dis[u] + eg[i].w){dis[v] = dis[u] + eg[i].w;pre[v] = i;if(!vis[v]){vis[v] = true;que[tail ++] = v;}}}vis[u] = false;}if(dis[vt] == MX) return false;return true;}void end(){int u, p, sum = MX;for(u = vt; u != vs; u = eg[eg[p].pre].v){p = pre[u];eg[p].c -=1;eg[eg[p].pre].c += 1;ans +=-1*eg[p].w; }}int main(){scanf("%d",&cas);while(cas--){k=0;ans = 0;memset(list,-1,sizeof(list));memset(hash,0,sizeof(hash));scanf("%d%d",&n,&K);int kk=1;for(int i=0;i<n;i++){scanf("%d%d%d",&inl[i].x,&inl[i].y,&inl[i].w);hash[inl[i].x]=hash[inl[i].y]=1;}for(int i=0;i<=100000;i++){if(hash[i]==1){hash[i]=kk++;}}for(int i=0;i<n;i++){inl[i].x=hash[inl[i].x];inl[i].y=hash[inl[i].y];}vs=0;vt=kk;for(int i=vs;i<vt;i++){add(i,i+1,K,0);}for(int i=0;i<n;i++){add(inl[i].x,inl[i].y,1,-inl[i].w);}while(spfa()) {end();}printf("%d\n",ans);}return 0;}