地址:https://nanti.jisuanke.com/t/31715
poj3680原题,数据都一样,是最小费用最大流摸板题
转载:https://blog.csdn.net/zhou_yujia/article/details/52411251
先看一下poj3680:
离散化所有区间的端点,把每个端点看做一个顶点,建立附加源S汇T。
1、从S到顶点1(最左边顶点)连接一条容量为K,费用为0的有向边。
2、从顶点2N(最右边顶点)到T连接一条容量为K,费用为0的有向边。
3、从顶点i到顶点i+1(i+1<=2N),连接一条容量为无穷大,费用为0的有向边。
4、对于每个区间[a,b],从a对应的顶点i到b对应的顶点j连接一条容量为1,费用为区间长度的有向边。
求最大费用最大流,最大费用流值就是最长k可重区间集的长度。
这个问题可以看做是求K条权之和最大的不想交路径,每条路径为一些不相交的区间序列。由于是最大费用流,两条路径之间一定有一些区间相交,可以看做事相交部分重复了2次,
而K条路经就是最多重复了K次。最简单的想法就是把区间排序后,不相交的区间之间连接一条边,由于每个区间只能用一次,所以要拆点,点内限制流量
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int MAXN = 405;
const int MAXM = 100005;
typedef struct Node{
int s,to,next,capacity,value;
}Node;
int n,k;
int ecnt;
Node node[MAXM];
int pre[MAXN];
int head[MAXN];
int dis[MAXN];
bool vis[MAXN];
int u[MAXN],v[MAXN],w[MAXN];
vector<int>ve;
map<int,int>mp;
void init()
{
ecnt = 0;
memset(head,-1,sizeof(head));
memset(node,0,sizeof(node));
}
void addEdge(int u,int v,int w,int c)
{
node[ecnt].to = v;
node[ecnt].s = u;
node[ecnt].capacity = c;//流量
node[ecnt].value = w;//路径长度是费用
node[ecnt].next = head[u];
head[u] = ecnt++;
node[ecnt].to = u;
node[ecnt].s = v;
node[ecnt].capacity = 0;//流量
node[ecnt].value = -w;//路径长度是费用
node[ecnt].next = head[v];
head[v] = ecnt++;
}
bool spfa(int s,int t,int nnum)
{
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
for(int i = 0;i <= nnum;++i)
{
dis[i] = inf;
}
queue<int>que;
que.push(s);
dis[s] = 0;
vis[s] = true;
while(!que.empty())
{
int temp = que.front();
que.pop();
vis[temp] = false;
for(int i = head[temp];i + 1;i = node[i].next)
{
if(node[i].capacity)
{
int ne = node[i].to;
if(dis[temp] + node[i].value < dis[ne]){
dis[ne] = dis[temp] + node[i].value;
pre[ne] = i;
if(!vis[ne]){
que.push(ne);
vis[ne] = true;
}
}
}
}
// for(int i = 0;i <= nnum;++i)
// cout << dis[i] << " ";
// cout << endl;
}
if(dis[t] == inf)
return false;
return true;
}
int getMincost(int s,int t,int nnum)
{
int ans_flow = 0;
int ans_cost = 0;
int temp,minc;
while(spfa(s,t,nnum))
{
// cout << 0 << endl;
temp = t;
minc = inf;
while(pre[temp] != -1)
{
minc = min(node[pre[temp]].capacity,minc);
temp = node[pre[temp]].s;
}
temp = t;
while(pre[temp] != -1)
{
node[pre[temp]].capacity -= minc;
int ss = pre[temp] ^ 1;
node[ss].capacity += minc;
temp = node[pre[temp]].s;
}
//cout << dis[t] << " " << minc << endl;
// for(int i = s;i <= t;++i)
// {
// cout << dis[i] << " ";
// }
// cout << endl;
ans_cost += dis[t] * minc;
}
return ans_cost;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
mp.clear();ve.clear();
init();
scanf("%d %d",&n,&k);
for(int i = 1;i <= n;++i)
{
scanf("%d %d %d",&u[i],&v[i],&w[i]);
ve.push_back(u[i]);
ve.push_back(v[i]);
}
sort(ve.begin(),ve.end());
ve.erase(unique(ve.begin(),ve.end()),ve.end());
int s = 0;
int t = ve.size() + 1;
int len = ve.size();
for(int i = 0;i < len;++i)
mp[ve[i]] = i + 1;
addEdge(s,1,0,k);
addEdge(ve.size(),t,0,k);
for(int i = 1;i < len;++i)
addEdge(i,i + 1,0,inf);
for(int i = 1;i <= n;++i)
addEdge(mp[u[i]],mp[v[i]],-w[i],1);
int res = getMincost(s,t,t);
printf("%d\n",-1 * res);
}
return 0;
}
再看F这道题,区间变了而已,改为把A[i] - 1 放入数组即可
注意:为什么建边把权值变为负呢,模板是最小费用最大流,每次用spfa找增广路径时,找到的是最小权值和,题意应该是找最大权值和
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
#include<queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int MAXN = 405;
const int MAXM = 100005;
typedef struct Node{
int s,to,next,capacity,value;
}Node;
int n,k,m;
int ecnt;
Node node[MAXM];
int pre[MAXN];
int head[MAXN];
int dis[MAXN];
bool vis[MAXN];
int u[MAXN],v[MAXN],w[MAXN];
vector<int>ve;
map<int,int>mp;
void init()
{
ecnt = 0;
memset(head,-1,sizeof(head));
memset(node,0,sizeof(node));
}
void addEdge(int u,int v,int w,int c)
{
node[ecnt].to = v;
node[ecnt].s = u;
node[ecnt].capacity = c;//流量
node[ecnt].value = w;//路径长度是费用
node[ecnt].next = head[u];
head[u] = ecnt++;
node[ecnt].to = u;
node[ecnt].s = v;
node[ecnt].capacity = 0;//流量
node[ecnt].value = -w;//路径长度是费用
node[ecnt].next = head[v];
head[v] = ecnt++;
}
bool spfa(int s,int t,int nnum)
{
memset(vis,0,sizeof(vis));
memset(pre,-1,sizeof(pre));
for(int i = 0;i <= nnum;++i)
{
dis[i] = inf;
}
queue<int>que;
que.push(s);
dis[s] = 0;
vis[s] = true;
while(!que.empty())
{
int temp = que.front();
que.pop();
vis[temp] = false;
for(int i = head[temp];i + 1;i = node[i].next)
{
if(node[i].capacity)
{
int ne = node[i].to;
if(dis[temp] + node[i].value < dis[ne]){
dis[ne] = dis[temp] + node[i].value;
pre[ne] = i;
if(!vis[ne]){
que.push(ne);
vis[ne] = true;
}
}
}
}
// for(int i = 0;i <= nnum;++i)
// cout << dis[i] << " ";
// cout << endl;
}
if(dis[t] == inf)
return false;
return true;
}
int getMincost(int s,int t,int nnum)
{
int ans_flow = 0;
int ans_cost = 0;
int temp,minc;
while(spfa(s,t,nnum))
{
// cout << 0 << endl;
temp = t;
minc = inf;
while(pre[temp] != -1)
{
minc = min(node[pre[temp]].capacity,minc);
temp = node[pre[temp]].s;
}
temp = t;
while(pre[temp] != -1)
{
node[pre[temp]].capacity -= minc;
int ss = pre[temp] ^ 1;
node[ss].capacity += minc;
temp = node[pre[temp]].s;
}
//cout << dis[t] << " " << minc << endl;
// for(int i = s;i <= t;++i)
// {
// cout << dis[i] << " ";
// }
// cout << endl;
ans_cost += dis[t] * minc;
}
return ans_cost;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
mp.clear();ve.clear();
init();
scanf("%d %d %d",&m,&k,&n);
for(int i = 1;i <= n;++i)
{
scanf("%d %d %d",&u[i],&v[i],&w[i]);
ve.push_back(u[i] - 1);
ve.push_back(v[i]);
}
sort(ve.begin(),ve.end());
ve.erase(unique(ve.begin(),ve.end()),ve.end());
int s = 0;
int t = ve.size() + 1;
int len = ve.size();
for(int i = 0;i < len;++i)
mp[ve[i]] = i + 1;
addEdge(s,1,0,k);
addEdge(ve.size(),t,0,k);
for(int i = 1;i < len;++i)
addEdge(i,i + 1,0,inf);
for(int i = 1;i <= n;++i)
addEdge(mp[u[i] - 1],mp[v[i]],-w[i],1);
int res = getMincost(s,t,t);
printf("%d\n",-1 * res);
}
return 0;
}