先说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. 利用python进行数据分析3_Pandas的数据结构

    Series #通过list构建Series ser_obj=pd.Series(range(10,20)) print(type(ser_obj))#<class 'pandas.core.s ...

  2. url编码和解码平台

    http://meyerweb.com/eric/tools/dencoder/

  3. QT +自定义控件-spin+slider

    动手实现自定义控件: 1.首先在ui界面中添加一个(Widget)容器类.如图中的1所示 2.在项目中添加一个SmallWidget类,如下: 3.接着在程序编辑界面进行程序编辑如下: #includ ...

  4. C++值传递、引用传递和指针传递

    #include<iostream> using namespace std; //值传递 void change1(int n){ cout<<"值传递--函数操作 ...

  5. [CODEVS] 2189 数字三角形W

    数字三角形 要求走到最后mod 100最大 可达性DP(好像是这样叫) 用bool数组f[i][j][k]表示 位置(i,j)能否得到k(mod 100意义下) 转移条件 f[i][j][k]=f[i ...

  6. redis集群理解

    Redis在3.0中也引入了集群的概念,用于解决一些大数据量和高可用的问题,但是,为了达到高性能的目的,集群不是强一致性的,使用的是异步复制,在数据到主节点后,主节点返回成功,数据被异步地复制给从节点 ...

  7. 利用js实现图片展开与收缩

    1.元素居中放大: 1>除了要改变元素的宽高以外,还要改变元素的定位(left,top),如果图片放大一倍,那么位移放大宽高的一半. 2>元素必须是定位的.所以,在css中设置为浮动布局, ...

  8. initcall机制

    参考:initcall机制 /* include/linux/init.h: */ /* For assembly routines */ #define __HEAD .section " ...

  9. 牛客网暑期ACM多校训练营(第五场) E room(最小费用最大流 , 最小权二分图匹配模板)

    链接: https://www.nowcoder.com/acm/contest/143/E 题意: 给定n个宿舍的新安排, 每个宿舍都有4个人, 问要至少有多少个人换位才能变成新安排. 可以建一个二 ...

  10. django的rest framework框架——分页、视图、路由、渲染器

    一.rest framework的分页 1.使用rest framework内置类PageNumberPagination实现分类 from django.conf.urls import url f ...