先说POJ3680:给n个有权(权<10w)开区间(n<200),(区间最多数到10w)保证数轴上所有数最多被覆盖k次的情况下要求总权最大,输出最大权。

思路:       限制的处理:s-->开始流量为k,要求总权最大,即费用最大,所以费用取负,最小费用最大流即可。对于输入区间[a,b]:w,添加边:a-->b,流量为1,费用为-w。

对于点i,i+1,添加边,费用为0,流量无穷。显然这种处理,限制了区间最多取k次,(流量控制),跑最大流能走添加的边尽量走,且越大越好(负数刚刚是最小费用),满足题意。但是TLE,因为w到10W,边10W,必然超时    ,所以点要处理,  所有点“压缩”,向前推进,只要存在的点,前一个向后一个连边即可,详见代码。

再看湘潭的这题: 问题相反:给n个有权(权<10w)开区间(n<2000),(区间最多数到10的9次),保证区间【1-,m】最少被覆盖k次的情况下要求总权最小,输出最小权。

思路:(感激zz1215的建图提示)    限制的处理:显然在出口处流量必需达到k才算有解。对于输入区间[a,b]:w,添加边:a-->b,流量为1,费用为w,但是这样处理,点都是离散的,根本没有体现连续性,

不可能像上题那样建图(否则费用为0),所以:这样:点I向它前一个点连边,费用为0,流量为无穷,这样巧妙的解决了离散点问题。跑最小费用即可。显然,之前要处理点。

#include<iostream>
#include<queue>
#include<cstdio>
using namespace std;
const int inf=0x3f3f3f3f;
const int t=100000;
int n,k;
int e[300001][4];int head[100101];int nume=0;
void inline adde(int from,int to,int w,int c)
{
e[nume][0]=to;e[nume][1]=head[from];head[from]=nume;
e[nume][2]=w;e[nume++][3]=c;
e[nume][0]=from;e[nume][1]=head[to];head[to]=nume;
e[nume][2]=-w;e[nume++][3]=0;
}
int inq[111005];int d[110000]; //spfa
bool spfa(int & sumcost) //每次求费用
{
int pre[110005];
int minf=inf;
int prv[110005];
for(int i=0;i<=t+1;i++)
{
inq[i]=0;d[i]=inf;
}
pre[0]=-1 ; prv[0]=-1; //路径中,分别记录到点i的边,和i之前的点。(这题如果用矩阵建图要方便)
queue<int>q;
q.push(0);inq[0]=1;d[0]=0;
while(!q.empty())
{
int cur=q.front();
q.pop();
inq[cur]=0;
for(int i=head[cur];i!=-1;i=e[i][1])
{
int v=e[i][0];
if(e[i][3]>0&&e[i][2]+d[cur]<d[v])
{
d[v]=e[i][2]+d[cur];
prv[v]=cur; //记录增广路
pre[v]=i;
if(!inq[v])
{
q.push(v);
inq[v]=1;
}
}
}
}
if(d[t+1]==inf)return 0; //无法增广
int cur=t+1; //目的点
while(cur!=0) //取路径上最小残流量边作为流量增广
{
minf=e[pre[cur]][3]<minf?e[pre[cur]][3]:minf;
cur=prv[cur];
}
cur=t+1;
while(cur!=0) //增广,改流量
{
e[pre[cur]][3]-=minf;
e[pre[cur]^1][3]+=minf;
cur=prv[cur];
}
sumcost+=d[t+1]*minf; //费用为单位费用(该路径下每条边单位流量之和)*流量
return 1;
}
void mincost(int & sumcost)
{
while(spfa(sumcost)) ; //无法增广为止
return ;
}
int hash[100011];
void clear()
{
nume=0;
for(int i=0;i<=t+1;i++)
{
hash[i]=head[i]=-1;
}
}
struct qujian
{
int a,b,w;
};
int main()
{
int T;
scanf("%d",&T);
for(int ii=1;ii<=T;ii++)
{
clear();
cin>>n>>k;
int a,b,w;
vector<qujian>qq(n);
vector<int>v;
for(int i=0;i<n;i++)
{
scanf("%d%d%d",&a,&b,&w);
hash[a]=hash[b]=1;
qq[i].a=a;qq[i].b=b;qq[i].w=w;
adde(a,b,-w,1);
}
for(int i=0;i<100010;i++) //处理“存在”的点
if(hash[i]==1)
{
v.push_back(i);
}
for(int i=0;i<v.size()-1;i++) //“存在”的点连边
{
adde(v[i],v[i+1],0,k);
}
adde(v[v.size()-1],t,0,k); //超级源汇点的边
adde(0,v[0],0,k);adde(t,t+1,0,k);
int sumcost=0;
mincost(sumcost);
cout<<-sumcost<<endl; //相反数
}
return 0;
}

湘潭:

#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
int n,k,m;
int countv=0;
int f[4009];
void getf(int x) // 把点1到10的9次(最多4000个点),压缩到4000以内,一一对应,以便建图。
{
if(x>m){f[countv]=x;return ;} //大于m的数没用,相当于m。
countv++;
f[countv]=x;
}
int getv(int x) //获取对应点
{
if(x>=m){return countv;}
for(int i=1;i<=countv;i++)
{
if(f[i]==x)return i;
}
}
int e[20001][4];int head[4005];int nume=0;
void inline adde(int from,int to,int w,int c)
{
e[nume][0]=to;e[nume][1]=head[from];head[from]=nume;
e[nume][2]=w;e[nume++][3]=c;
e[nume][0]=from;e[nume][1]=head[to];head[to]=nume;
e[nume][2]=-w;e[nume++][3]=0;
}
int inq[4005];int d[4005]; //spfa
bool spfa(int & sumcost,int &sumflow) //每次求费用
{
int pre[4005];
int minf=inf;
int prv[4005];
for(int i=0;i<=countv+4;i++)
{
inq[i]=0; d[i]=inf;
}
pre[0]=-1 ; prv[0]=-1; //路径中,分别记录到点i的边,和i之前的点。(这题如果用矩阵建图要方便)
queue<int>q;
q.push(0);inq[0]=1;d[0]=0;
while(!q.empty())
{
int cur=q.front();
q.pop();
inq[cur]=0;
for(int i=head[cur];i!=-1;i=e[i][1])
{
int v=e[i][0];
if(e[i][3]>0&&e[i][2]+d[cur]<d[v])
{
d[v]=e[i][2]+d[cur];
prv[v]=cur; //记录增广路
pre[v]=i;
if(!inq[v])
{
q.push(v);
inq[v]=1;
}
}
}
}
if(d[countv+1]==inf)return 0; //无法增广
int cur=countv+1; //目的点
while(cur!=0) //取路径上最小残流量边作为流量增广
{
minf=e[pre[cur]][3]<minf?e[pre[cur]][3]:minf;
cur=prv[cur];
}
cur=countv+1;
while(cur!=0) //增广,改流量
{
e[pre[cur]][3]-=minf;
e[pre[cur]^1][3]+=minf;
cur=prv[cur];
}
sumcost+=d[countv+1]*minf; //费用为单位费用(该路径下每条边单位流量之和)*流量
sumflow+=minf;
return 1;
}
void mincost(int & sumcost,int & sumflow)
{
while(spfa(sumcost,sumflow)) ; //无法增广为止
return ;
}
void clear()
{
nume=countv=0;
for(int i=0;i<=4003;i++)
{
head[i]=-1;
f[i]=0;
}
}
struct qujian
{
int a,b,w;
};
int main()
{
int T;
cin>>T;
for(int ii=1;ii<=T;ii++)
{
clear();
cin>>n>>k>>m;
int a,b,w;
vector<int>v;
vector<qujian>qq(n);
for(int i=0;i<n;i++)
{
cin>>a>>b>>w;
v.push_back(a);
v.push_back(b);
qq[i].a=a;qq[i].b=b;qq[i].w=w;
}
sort(v.begin(),v.end()); //从小到大处理点
for(int i=0;i<v.size();i++)
{
getf(v[i]);
}
for(int i=0;i<n;i++)
{
int t1=getv(qq[i].a);
int t2=getv(qq[i].b);
adde(t1,t2,qq[i].w,1); //注意点:若使用adde(getv(a),getv(b),w,1)参数是从右往左开始赋值传递的!!!
}
for(int i=1;i<countv;i++)
{
adde(i+1,i,0,inf); //注意点:若使用adde(getv(a),getv(b),w,1)参数是从右往左开始赋值传递的!!!
}
adde(0,1,0,inf);adde(countv,countv+1,0,k);
int sumcost=0; int sumflow=0;
mincost(sumcost,sumflow);
cout<<"Case "<<ii<<": ";
if(sumflow!=k) //到不了k,无解
{
cout<<-1<<endl;
}
else
{
cout<<sumcost<<endl;
}
}
return 0;
}

2014湘潭全国邀请赛I题 Intervals /POJ 3680 / 在限制次数下取有权区间使权最大/小问题(费用流)的更多相关文章

  1. 2014上海全国邀请赛题解 HDOJ 5090-5099

    HDOJ 5090 水题.从小到大排序,能够填充达到符合条件的.先填充好.填充之后进行调整. 传送门:pid=5090">点击打开链接 #include <cstdio> ...

  2. HDU 4597 Play Game 2013 ACM-ICPC吉林通化全国邀请赛H题

    九野的博客,转载请注明出处:  http://blog.csdn.net/acmmmm/article/details/10833941 题意:给定T个测试数据,下面有2副牌,每副n张,每张都有一个分 ...

  3. 湘潭oj1203/邀请赛A题 数论+java大数

    求 n%1+n%2+n%3+n%4+.........n%n=,n<=10^12次. 开始时盲目地找规律,结果一无所获.后来经学长点拨,天资愚钝,搞了半天才明白. 先上图: 对于该题,在求区间( ...

  4. hdu - 6281,2018CCPC湖南全国邀请赛F题,快排

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6281 题意: 根据已给出的式子,进行排序,然后输出排完序后原先的下表. 题解:用结构体保存,在用结构体 ...

  5. hdu - 6277,2018CCPC湖南全国邀请赛B题,找规律,贪心找最优.

    题意: 给出N个小时,分配这些小时去写若干份论文,若用1小时写一份论文,该论文会被引用A次,新写一篇论文的话,全面的论文会被新论文引用一次. 找最大的H,H是指存在H遍论文,而且这些论文各被引用大于H ...

  6. hdu - 6276,2018CCPC湖南全国邀请赛A题,水题,二分

    题意: 求H的最大值,  H是指存在H篇论文,这H篇被引用的次数都大于等于H次. 思路:题意得,  最多只有N遍论文,所以H的最大值为N, 常识得知H的最小值为0. 所以H的答案在[0,N]之间,二分 ...

  7. hdu - 6282,2018CCPC湖南全国邀请赛G题,字符串,规律

    HDU – 6282 http://acm.hdu.edu.cn/showproblem.php?pid=6282 by Hzu_Tested 题意:给出两个字符串S和T,只由a,b,c三种字符组成( ...

  8. Intervals POJ - 3680 (MCMF)

    给你一些区间,每个区间都有些价值.取一个区间就能获得对应的价值,并且一个点不能覆盖超过k次,问你最大的价值是多少. 我们可以把这些区间放到一维的轴上去,然后我们可以把它看成一个需要从左到右的过程,然后 ...

  9. Intervals POJ - 3680

    传送门 给定数轴上n个带权区间$[l_i,r_i]$,权值为$w_i$ 选出一些区间使权值和最大,且每个点被覆盖次数不超过k次. 离散+拆点,最大费用可行流(跑到费用为负为止) 第一部分点按下标串起来 ...

随机推荐

  1. Bootstrap历练实例:输入框组的大小

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  2. ios 之CGRectMake

    首先要弄懂几个基本的概念. 一)三个结构体:CGPoint.CGSize.CGRect 1.  CGPoint [plain] view plaincopy   /* Points. */ struc ...

  3. 高德定位腾讯定位在APP上无法开启定位权限的解决方案

    [备注]公司项目中遇到的问题,如果你在团队工作其中定有不少配合方面的问题,其中的思路是可以借鉴的,因为这也许正是你们现在遇到的问题,总结的不好的地方还请多多指教 因为项目需求的确定,定位成了必不可少的 ...

  4. Python操作微信跳一跳

    “跳一跳”这个东西还是今天刚接触到的,看到了python群中有人再问“微信跳一跳的外挂有人写了没”,“早就有了”,“github”,“等着出个更详细的教程教程没看懂,主要没有用过adb”. 不过没关系 ...

  5. Centos7下安装iptables防火墙

    说明:centos7默认使用的firewalld防火墙,由于习惯使用iptables做防火墙,所以在安装好centos7系统后,会将默认的firewall关闭,并另安装iptables进行防火墙规则设 ...

  6. Python的两个爬虫框架PySpider与Scrapy安装

    Python的两个爬虫框架PySpider与Scrapy安装 win10安装pyspider: 最好以管理员身份运行CMD,不然可能会出现拒绝访问文件夹的情况! pyspider:pip instal ...

  7. LeetCode(137) Single Number II

    题目 Given an array of integers, every element appears three times except for one. Find that single on ...

  8. 快速入门Matplotlib

    十分钟快速入门Matplotlib 函数式绘图 这个库主要有两种绘图方式,一种是像这样的类matlab的函数式绘图方法. import matplotlib.pyplot as plt import ...

  9. PAT Basic 1040

    1040 有几个PAT 字符串APPAPT中包含了两个单词“PAT”,其中第一个PAT是第2位(P),第4位(A),第6位(T):第二个PAT是第3位(P),第4位(A),第6位(T). 现给定字符串 ...

  10. Python基础数据类型之字符串

    Python基础数据类型之字符串 一.Python如何创建字符串 在python中用引号将一些文本包起来就构成了字符串(引号可以是单引号.双引号.单三引号,双三引号,它们是完全相同的) >> ...