标签:while 代码 流量 n+2 for mem mes main als
有n个线段\((a_i,b_i)\),每个线段有一个权值\(w_i\)。要求选若干个线段,使得数轴上每个点至多被k个线段包含。
可以把权值取负值作为费用求费用流,这题有两种建图方式
离散化数据,对每个点i连一条i到i+1的边,流量为k,费用为0。对于所有线段连一条\(a_i\)到\(b_i\)的边,流量为1,费用为-\(w_i\)。那么,对每个点可以选择以这个点为起点的线段或者不选,如果选了就需要花费1个流量,且直到线段终点都只剩下了k-1个流量,所以可以确保每一个点最多被k条线段覆盖。
考虑把线段覆盖改为找k个不相交的线段集合。把每个点拆成两个,这样就可以对所有不相交的线段进行连边。并且对每个线段的起点终点连边(费用为-w),源点对线段起点连边,线段终点对汇点连边。这样线段集合就表示为了一条增广路。最后在源点或汇点加一个限制(流量为k的边)就可以了。
#include<vector>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=200+5;
int a[maxn],b[maxn],ww[maxn];
vector<int>vec;
struct Edge{
int v,w,c,next;
}edge[maxn*6];
int head[maxn*2],ecnt;
void add(int u,int v,int w,int c)
{
edge[ecnt]=(Edge){v,w,c,head[u]};
head[u]=ecnt++;
}
const int inf=0x3f3f3f3f;
int S,T;
int fa[maxn*2],fai[maxn*2];
int dis[maxn*2], vis[maxn*2];
bool spfa()
{
memset(dis,0x3f,sizeof(dis));
queue<int>q;
dis[S]=0;
for(q.push(S);!q.empty();q.pop())
{
int u=q.front();
vis[u]=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(!edge[i].w)continue;
if(dis[v]>dis[u]+edge[i].c)
{
dis[v]=dis[u]+edge[i].c;
fa[v]=u;
fai[v]=i;
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
return dis[T]!=inf;
}
int cost()
{
int ans=0,flow=inf;
for(int u=T;u!=S;u=fa[u])
flow=min(flow,edge[fai[u]].w);
for(int u=T;u!=S;u=fa[u])
{
edge[fai[u]].w-=flow;
edge[fai[u]^1].w+=flow;
ans+=flow*edge[fai[u]].c;
}
return ans;
}
int main()
{
int ca;
scanf("%d",&ca);
while(ca--)
{
int N,K;
vec.clear();
memset(head,-1,sizeof(head));
ecnt=0;
scanf("%d%d",&N,&K);
for(int i=1;i<=N;i++)
{
scanf("%d%d%d",&a[i],&b[i],&ww[i]);
vec.push_back(a[i]);
vec.push_back(b[i]);
}
sort(vec.begin(),vec.end());
int n=unique(vec.begin(),vec.end())-vec.begin();
vec.resize(n);
for(int i=1;i<=N;i++)
{
a[i]=lower_bound(vec.begin(),vec.end(),a[i])-vec.begin()+1;
b[i]=lower_bound(vec.begin(),vec.end(),b[i])-vec.begin()+1;
add(a[i],b[i],1,-ww[i]);
add(b[i],a[i],0,ww[i]);
}
for(int i=0;i<=n;i++)
{
add(i,i+1,K,0);
add(i+1,i,0,0);
}
S=0;T=n+1;
int ans=0;
while(spfa())
ans+=cost();
printf("%d\n",-ans);
}
return 0;
}
#include<vector>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=200+5;
int a[maxn],b[maxn],ww[maxn];
struct Edge{
int v,w,c,next;
}edge[maxn*maxn*2];
int head[maxn*2],ecnt;
void add(int u,int v,int w,int c)
{
edge[ecnt]=(Edge){v,w,c,head[u]};
head[u]=ecnt++;
edge[ecnt]=(Edge){u,0,-c,head[v]};
head[v]=ecnt++;
}
const int inf=0x3f3f3f3f;
int S,T;
int fa[maxn*2],fai[maxn*2];
int dis[maxn*2], vis[maxn*2];
bool spfa()
{
memset(dis,0x3f,sizeof(dis));
queue<int>q;
dis[S]=0;
for(q.push(S);!q.empty();q.pop())
{
int u=q.front();
vis[u]=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].v;
if(!edge[i].w)continue;
if(dis[v]>dis[u]+edge[i].c)
{
dis[v]=dis[u]+edge[i].c;
fa[v]=u;
fai[v]=i;
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
return dis[T]!=inf;
}
int cost()
{
int ans=0,flow=inf;
for(int u=T;u!=S;u=fa[u])
flow=min(flow,edge[fai[u]].w);
for(int u=T;u!=S;u=fa[u])
{
edge[fai[u]].w-=flow;
edge[fai[u]^1].w+=flow;
ans+=flow*edge[fai[u]].c;
}
return ans;
}
int main()
{
int ca;
scanf("%d",&ca);
while(ca--)
{
int N,K;
memset(head,-1,sizeof(head));
ecnt=0;
scanf("%d%d",&N,&K);
S=0,T=2*N+2;
for(int i=1;i<=N;i++)
{
scanf("%d%d%d",&a[i],&b[i],&ww[i]);
add(i*2,i*2+1,1,-ww[i]);
add(i*2,i*2+1,inf,0);//
add(S+1,i*2,1,0);
add(i*2+1,T,1,0);
}
add(S,S+1,K,0);
for(int i=1;i<=N;i++)
for(int j=1;j<=N;j++)
if(b[i]<=a[j])
add(2*i+1,2*j,inf,0);
int ans=0;
while(spfa())
ans+=cost();
printf("%d\n",-ans);
}
return 0;
}
标签:while 代码 流量 n+2 for mem mes main als
原文地址:https://www.cnblogs.com/intmian/p/12198798.html