网络流24题 部分总结
网络流24题 部分总结
慢慢写吧。。。
以前做过一些了;
然后发现也做了不少了,集中写一下。
警告:
-
题目按照随机顺序排列。
-
文章中只有建模的方法。
最小路径覆盖问题
http://cogs.pro:8080/cogs/problem/problem.php?pid=728
题目即题解。。。
// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cstring>
#define File
#define Fname "path3"
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
#define t (dis[i])
typedef long long ll;
il int gi(){
rg int x=0;rg char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x;
}
const int maxn=151<<1,maxm=6002;
int id=0,fir[maxn],dis[maxm],nxt[maxm];
il vd add(int a,int b){
nxt[++id]=fir[a],fir[a]=id,dis[id]=b;
}
bool vis[maxn];int match[maxn],in[maxn],to[maxn];
il bool dfs(int now){
erep(i,now)
if(!vis[t]){
vis[t]=1;
if(match[t]==-1||dfs(match[t])){match[t]=now;return 1;}
}
return 0;
}
int main(){
freopen(Fname".in","r",stdin);
freopen(Fname".out","w",stdout);
rg int n=gi(),m=gi();
while(m--){rg int i=gi(),j=gi();add(i,j+n);}
memset(match,-1,sizeof match);
int ans=0;
drep(i,n,1){
memset(vis,0,sizeof vis);
vis[i]=1;if(dfs(i))++ans;
}
drep(i,n+n,n+1)if(match[i]+1)to[match[i]]=i-n,in[i-n]=1;
rep(i,1,n)if(!in[i]){
int now=i;printf("%d ",now);
while(to[now])now=to[now],printf("%d ",now);
puts("");
}
printf("%d\n",n-ans);
return 0;
}
魔术球问题
http://cogs.pro:8080/cogs/problem/problem.php?pid=396
我会打表!
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int n,ans[]={233333,1,3,7,11,17,23,31,39,49,59,71,83,97,111,127,143,161,179,199,219,241,263,287,311,337,363,391,419,449,479,511,543,577,611,647,683,721,759,799,839,881,923,967,1011,1057,1103,1151,1199,1249,1299,1351,1403,1457,1511,1567,1623,1681,1739,1799,1859};
int main() {
freopen("balla.in","r",stdin);
freopen("balla.out","w",stdout);
scanf("%d",&n);
printf("%d",ans[n]);
return 0;
}
正解是累加答案然后连边增广。不知道这是不是我当年写的了。丑的一批。唉。
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#define re register
#define inf 1<<29
#define il inline
#define rep(i,a,b) for(register int i=a;i<=b;++i)
#define file(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;
const int N=1610;
struct Edge{
int to,net,flow,cap;
int fr;
}e[N*N];
int head[N*2],num_e,n,m;
il void add(int x,int y,int c){
e[++num_e].to=y,e[num_e].cap=c,e[num_e].net=head[x],head[x]=num_e;
e[num_e].fr=x;
}
const int oh=1604;
int s,t;
inline int gi() {
re int res=0,f=1;re char ch=getchar();while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();while(ch>='0'&&ch<='9')res=res*10+ch-'0',ch=getchar();return res*f;
}
int lev[N*2];
il bool bfs(){
queue<int> q;
memset(lev,0,sizeof(lev));
q.push(s);lev[s]=1;re int u;
while(!q.empty()){
u=q.front();q.pop();
for(int i=head[u];i!=-1;i=e[i].net){
int to=e[i].to;
if(!lev[to]&&e[i].cap>e[i].flow){
lev[to]=lev[u]+1;
q.push(to);
if(lev[t]) return true;
}
}
}
return false;
}
int dfs(int x,int f){
if(x==t) return f;
int tag=0;
for(int i=head[x];i!=-1;i=e[i].net){
int to=e[i].to;
if(lev[to]==lev[x]+1&&e[i].cap>e[i].flow){
int c=dfs(to,min(e[i].cap-e[i].flow,f-tag));
e[i].flow+=c;
e[i^1].flow-=c;
tag+=c;
if(tag==f) break;
}
}
if(!tag) lev[x]=0;
return tag;
}
int Dinic(){
re int flow=0;
while(bfs())
flow+=dfs(s,inf);
return flow;
}
bool pd[N*2];
int nxt[N*2];
void get_ans(int n){
for(re int i=0;i<=num_e;i+=2) {
if(e[i].fr==s||e[i].to==t||e[i].cap!=e[i].flow) continue;
nxt[e[i].fr]=e[i].to-oh;
pd[e[i].to-oh]=1;
}
for(re int i=1;i<=n;i++)
if(!pd[i]){
re int u=i;
printf("%d ",u);
while(nxt[u]) u=nxt[u],printf("%d ",u);
puts("");
}
}
void init(){
e[num_e-1].cap=0,e[num_e].cap=0;
rep(i,0,num_e) e[i].flow=0;
Dinic();
}
int main(){
memset(head,-1,sizeof(head));num_e=-1;
s=0,t=3210;
re int i=0;
m=gi();
int f=0;
for(;;){
i++;
rep(j,1,i-1) if((int)sqrt(i+j)*(int)sqrt(i+j)==i+j) add(j,i+oh,1),add(i+oh,j,0);
add(s,i,1),add(i,s,0);
add(i+oh,t,1),add(t,i+oh,0);
f+=Dinic();
if(i-f>m) break;
}
printf("%d\n",i-1);
return 0;
}
搭配飞行员
http://cogs.pro:8080/cogs/problem/problem.php?pid=14
记得是我第一次写匈牙利把。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define t (dis[i])
using namespace std;
const int maxn=110,maxm=510<<1;
void init();
void work();
bool dfs(int);
int main() {
init(),work();
return 0;
}
inline int gi();
int n,n1,m,fir[maxn],nxt[maxm],dis[maxm];
inline void adde(int a,int b,int id) {
nxt[id]=fir[a],fir[a]=id,dis[id]=b;
}
bool vis[maxn];
int T[maxn];
void work() {
memset(T,-1,sizeof(T));
int ans=0;
for(int i=1; i<=n1; i++) {
memset(vis,0,sizeof(vis));
ans+=dfs(i);
}
printf("%d\n",ans);
}
void init() {
scanf("%d%d",&n,&n1);
int a,b;
while(scanf("%d%d",&a,&b)==2)adde(a,b,++m),adde(b,a,++m);
}
bool dfs(int now) {
for(int i=fir[now]; i; i=nxt[i])
if(!vis[t]) {
vis[t]=1;
if(T[t]==-1||dfs(T[t])){
T[t]=now;return 1;
}
}
return 0;
}
骑士共存
http://cogs.pro:8080/cogs/problem/problem.php?pid=746
你看他都帮你涂好颜色了
能互相攻击就连边,显然二分图,n*m-匹配=答案
#include<cstdio>
#include<algorithm>
#include<cstring>
#define check(x,y) (x>0&&x<=n&&y>0&&y<=n)
using namespace std;
const int X[]= {99999,-1,1,2,2};
const int Y[]= {888888888,2,2,1,-1};
int id[201][201],fir[40001],nxt[40001*8*2],dis[40001*8*2];
inline int gi() {
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')f=(ch=='-')?-1:f,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*f;
}
int iiddd=0;
inline void adde(int a,int b) {
nxt[++iiddd]=fir[a],fir[a]=iiddd,dis[iiddd]=b;
}
int N=0,n,m;
inline void init() {
int a,b;
n=gi(),m=gi();
for(int i=1; i<=m; i++)a=gi(),b=gi(),id[a][b]=-1;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(id[i][j]!=-1)id[i][j]=++N;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)if(id[i][j]>0)
for(int k=1; k<5; k++)
if(check((i+X[k]),(j+Y[k]))&&id[i+X[k]][j+Y[k]]>0) {
adde(id[i][j],id[i+X[k]][j+Y[k]]);
adde(id[i+X[k]][j+Y[k]],id[i][j]);
}
}
int match[40001],vis[40001];
inline bool dfs(int now) {
for(int i=fir[now]; i; i=nxt[i])
if(!vis[dis[i]]) {
int t=dis[i];
vis[t]=1;
if(match[t]==-1||dfs(match[t])) {
match[t]=now;
return 1;
}
}
return 0;
}
inline void hun() {
int ans=0;
memset(match,-1,sizeof match);
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if((i+j)&1) {
memset(vis,0,sizeof vis);
ans+=dfs(id[i][j]);
}
printf("%d",N-ans);
}
int main() {
init(),hun();
return 0;
}
我以前代码写的好丑啊
最长递增子序列
http://cogs.pro:8080/cogs/problem/problem.php?pid=731
- 动态规划秒之。
- i向满足\(j>i且x_j>x_i\)的j连边;
若\(f_i=s\),就i向T连边;
S向每个点连边。
权值均为1。 - 同2
S向1连的边权值改为inf;
若n向T有连边,权值改为inf。 - 有个坑点,这是最长不下降子序列。
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define t (dis[i])
using namespace std;
inline int gi() {
int x=0,f=1;
char ch=getchar();
while(ch>'9'||ch<'0')f=(ch=='-')?-1:f,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*f;
}
inline void Dp();
inline void solve(int);
int X[501],F[501];
int n,K,S,T;
int main() {
n=gi();
for(int i=1; i<=n; i++)X[i]=gi();
Dp();
S=n+1,T=n+2,solve(1),solve(1000);
return 0;
}
const int maxn=521,maxm=400001<<1;
int fir[maxn],dis[maxm],w[maxm],nxt[maxm],dep[maxn];
inline void Dp() {
int ans=0;
for(int i=1; i<=n; i++) {
F[i]=1;
for(int j=1; j<i; j++)if(X[j]<=X[i])F[i]=max(F[i],F[j]+1);
ans=max(F[i],ans);
}
printf("%d\n",K=ans);
}
int Index=1;
inline void adde(int a,int b,int ww) {
nxt[++Index]=fir[a],fir[a]=Index,dis[Index]=b,w[Index]=ww;
if(ww)adde(b,a,0);
}
inline bool BFS() {
queue<int>bfs;
memset(dep,0,sizeof dep);
bfs.push(S);
bool yes[600]= {0};
yes[S]=1,dep[S]=0;
while(!bfs.empty()) {
int now=bfs.front();
for(int i=fir[now]; i; i=nxt[i])
if(w[i]>0&&!yes[t])
yes[t]=1,bfs.push(t),dep[t]=dep[now]+1;
bfs.pop();
}
return yes[T];
}
inline int Dinic(int now,int h) {
if(now==T)return h;
int ans=0;
for(int i=fir[now]; i; i=nxt[i])
if(w[i]>0&&dep[t]==dep[now]+1) {
int D=Dinic(t,min(h,w[i]));
w[i]-=D,w[i^1]+=D,ans+=D,h-=D;
if(h==0)return ans;
}
return ans;
}
inline void solve(int hehe) {
memset(fir,0,sizeof fir);
Index=1;
for(int i=1; i<n; i++)
for(int j=i+1; j<=n; j++)
if(X[i]<=X[j]&&F[i]+1==F[j])adde(i,j,1);
if(hehe^1) {
adde(S,1,hehe);
for(int i=2; i<=n; i++)if(F[i]==1)adde(S,i,1);
for(int i=1; i<n; i++)if(F[i]==K)adde(i,T,1);
if(F[n]==K)adde(n,T,hehe);
} else {
for(int i=1; i<=n; i++)if(F[i]==1)adde(S,i,1);
for(int i=1; i<=n; i++)if(F[i]==K)adde(i,T,1);
}
int ans=0;
while(BFS())ans+=Dinic(S,10000000);
printf("%d\n",ans);
}
方格取数问题
懒得放链接了。。
结论题。。
先染色,S向黑点连边,权值为这个数;白点向T点连边,权值为这个数。相邻的点连边,权值为inf。
总数字-最大流=答案。。。
// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define rep(a,b,c) for(rg int a=b;a<=c;a++)
#define drep(a,b,c) for(rg int a=b;a>=c;a--)
#define erep(a,b) for(rg int a=fir[b];a;a=nxt[a])
#define il inline
#define rg register
#define vd void
#define t (dis[i])
typedef long long ll;
il int gi(){
rg int x=0;rg char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x;
}
const int maxn=30*30+10,maxm=30*30*4+100,S=1,T=2;
int fir[maxn],nxt[maxm],dis[maxm],w[maxm],id=1;
int X[]={23333,0,0,1,-1},Y[]={23333,1,-1,0,0};
il vd add(int a,int b,int c){
nxt[++id]=fir[a],fir[a]=id,dis[id]=b,w[id]=c;
if(c)add(b,a,0);
}
int num[31][31];
bool vis[maxn];
il int ff(int now,int end,int minn){
if(now==end)return minn;
vis[now]=1;
erep(i,now)
if(!vis[dis[i]]&&w[i]){
rg int down=ff(dis[i],end,min(minn,w[i]));
if(down){w[i]-=down,w[i^1]+=down;return down;}
}
return 0;
}
int main(){
int n=gi(),m=gi(),Id=2,sum=0,a=0;
rep(i,1,n)rep(j,1,m){
num[i][j]=++Id;
sum+=a=gi();
if((i+j)&1)add(S,num[i][j],a);
else add(num[i][j],T,a);
}
rep(i,1,n)rep(j,1,m)if((i+j)&1)rep(k,1,4)
if(num[i+X[k]][j+Y[k]])add(num[i][j],num[i+X[k]][j+Y[k]],666666666);
int flow,Flow=0;
while(flow=ff(S,T,666666666))Flow+=flow,memset(vis,0,sizeof vis);
printf("%d\n",sum-Flow);
return 0;
}
汽车加油行驶
最短路乱入。。
设f(x,y,k)为走到点(x,y),且还能走k条边的最小费用。
依题意连边就好了。。。
好像n<=100(把)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define MAX 120
inline int read()
{
int x=0,t=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
struct Line
{
int v,next,w;
}e[MAX*MAX*MAX];
int h[MAX*MAX],cnt=1,tot;
int m[MAX*MAX],g[MAX][MAX],n,K,A,B,C;
bool vis[MAX*MAX][15];
inline void Add(int u,int v,int w)
{
e[cnt]=(Line){v,h[u],w};h[u]=cnt++;
}
int dis[MAX*MAX][15];
void SPFA()
{
memset(dis,63,sizeof(dis));
dis[g[1][1]][K]=0;
queue<int> Q,Q1;
Q.push(g[1][1]);Q1.push(K);
while(!Q.empty())
{
int u=Q.front(),t=Q1.front();
Q.pop();Q1.pop();
if(t!=0)
{
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v,gg=t-1,Dis=dis[u][t]+e[i].w;
if(m[v])gg=K,Dis+=A;
if(dis[v][gg]>Dis)
{
dis[v][gg]=Dis;
if(!vis[v][gg])vis[v][gg]=true,Q.push(v),Q1.push(gg);
}
}
}
int v=u,gg=K,Dis=dis[u][t]+C+A;
if(dis[v][gg]>Dis)
{
dis[v][gg]=Dis;
if(!vis[v][gg])vis[v][gg]=true,Q.push(v),Q1.push(gg);
}
vis[u][t]=false;
}
}
int main()
{
n=read();K=read();A=read();B=read();C=read();
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
g[i][j]=++tot,m[g[i][j]]=read();;
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
{
if(i!=n)Add(g[i][j],g[i+1][j],0);
if(j!=n)Add(g[i][j],g[i][j+1],0);
if(i!=1)Add(g[i][j],g[i-1][j],B);
if(j!=1)Add(g[i][j],g[i][j-1],B);
}
SPFA();
int ans=1e9;
for(int i=0;i<=K;++i)ans=min(ans,dis[g[n][n]][i]);
printf("%d\n",ans);
return 0;
}
数字梯形
需要用到拆点的思想。。。
本来是每个点向下面两个点连边的,然而这样无法限制节点的流量,于是拆点
不想写了。。
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#define inf 10000000
#define up +0
#define down +1
#define t (dis[i])
const int maxn=1001<<1,maxm=10000<<1,S=2000,T=2001;
using namespace std;
int fir[maxn],dis[maxm],w[maxm],cost[maxm],nxt[maxm],id=1,m,n;
int INDEX=0;
inline void add(int a,int b,int c,int d,int e=0){
nxt[++id]=fir[a],fir[a]=id,dis[id]=b,w[id]=c,cost[id]=d;
if(c)add(b,a,0,e);
}
int num[21][41],Index[21][41];
inline void build(int a,int b){
memset(fir,0,sizeof fir);
for(int i=1;i<=m;i++)add(S,Index[1][i]up,1,0);
for(int i=1;i<=m+n-1;i++)add(Index[n][i]down,T,a,0);
for(int i=1;i<n;i++)
for(int j=1;j<m+i;j++){
add(Index[i][j]up,Index[i][j]down,a,-num[i][j],num[i][j]);
add(Index[i][j]down,Index[i+1][j]up,b,0);
add(Index[i][j]down,Index[i+1][j+1]up,b,0);
}
for(int j=1;j<m+n;j++)
add(Index[n][j]up,Index[n][j]down,a,-num[n][j],num[n][j]);
}
int que[maxn],vis[maxn],pre[maxn],Dis[maxn];
inline bool spfa(){
int hd=1,tl=1;
for(int i=1;i<=INDEX;i++)Dis[i]=inf;
memset(vis,0,sizeof vis);
Dis[T]=inf,Dis[S]=0,que[tl++]=S,vis[S]=1;
while(hd^tl){
int now=que[hd];
for(int i=fir[now];i;i=nxt[i])
if(w[i]>0&&Dis[t]>Dis[now]+cost[i]){
Dis[t]=Dis[now]+cost[i],pre[t]=i;
if(!vis[t])vis[t]=1,que[tl]=t,tl=(tl+1)%maxn;
}
vis[now]=0,hd=(hd+1)%maxn;
}
return Dis[T]!=inf;
}
inline int end(int&flow,int sum=inf,int ret=0){
for(int now=T,p;now^S;now=dis[p^1])p=pre[now],sum=min(sum,w[p]);
for(int now=T,p;now^S;now=dis[p^1])p=pre[now],w[p]-=sum,w[p^1]+=sum,ret+=cost[p];
flow+=sum;return ret*sum;
}
inline int maxflow(int ans=0,int flow=0){
while(spfa())ans+=end(flow);
return -ans;
}
int main(){
scanf("%d%d",&m,&n);
for(int i=0;i<n;i++)
for(int j=1;j<=m+i;j++)
scanf("%d",&num[i+1][j]),Index[i+1][j]=++INDEX,++INDEX;
build(1,1),printf("%d\n",maxflow());
build(inf,1),printf("%d\n",maxflow());
build(inf,inf),printf("%d\n",maxflow());
return 0;
}
分配问题
我真的懒得写了。。。
最长k可重区间集
离散化,值域[1,p]
之后从i向i+1(0<i<p)连边(容量为k),S向0连边(容量为k),p向T连边(容量为k)
// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cstring>
#define il inline
#define rg register
#define vd void
#define sta static
typedef long long ll;
il int gi(){
rg int x=0,f=1;rg char ch=getchar();
while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int maxn=501,maxN=1100,S=0,T=maxN-1,maxm=((1001+501)<<1)+233;
int l[maxn],r[maxn],num[maxn<<1];
int fir[maxN],dis[maxm],nxt[maxm],w[maxm],cost[maxm],id=1;
il vd link(const int&x,const int&y,const int&_w,const int&_c){nxt[++id]=fir[x],fir[x]=id,dis[id]=y,w[id]=_w,cost[id]=_c;}
il vd Link(int x,int y,int _w,int _c){link(x,y,_w,_c),link(y,x,0,-_c);}
il bool SPFA(int&c){
sta int que[maxN],hd,tl,dist[maxN],lst[maxN];
sta bool inque[maxN]={0};
memset(dist,63,sizeof dist);memset(lst,0,sizeof lst);
hd=tl=0;que[tl++]=S;inque[S]=1;dist[S]=0;
while(hd^tl){
sta int x;x=que[hd];
for(rg int i=fir[x];i;i=nxt[i])
if(dist[x]+cost[i]<dist[dis[i]]&&w[i]){
dist[dis[i]]=dist[x]+cost[i];lst[dis[i]]=i;
if(!inque[dis[i]])inque[dis[i]]=1,que[tl++]=dis[i],tl%=maxN;
}
++hd;hd%=maxN;inque[x]=0;
}
if(lst[T]==0)return 0;
int flow=233333333;
for(rg int i=lst[T];i;i=lst[dis[i^1]])flow=std::min(flow,w[i]);
for(rg int i=lst[T];i;i=lst[dis[i^1]])c+=cost[i]*flow,w[i]-=flow,w[i^1]+=flow;
return 1;
}
int main(){
int n=gi(),k=gi(),p;
for(rg int i=1;i<=n;++i){
l[i]=gi(),r[i]=gi();
num[++num[0]]=l[i],num[++num[0]]=r[i];
}
std::sort(num+1,num+2*n+1);
p=std::unique(num+1,num+2*n+1)-num-1;
for(rg int i=1;i<=n;++i)l[i]=std::lower_bound(num+1,num+p+1,l[i])-num,r[i]=std::lower_bound(num+1,num+p+1,r[i])-num;
for(rg int i=0;i<p;++i)Link(i,i+1,k,0);
for(rg int i=1;i<=n;++i)Link(l[i],r[i],1,-(num[r[i]]-num[l[i]]));
Link(p,T,k,0);
int c=0;while(SPFA(c));
printf("%d\n",-c);
return 0;
}
餐巾计划
费用流裸题(要烂尾了)
#include<cstdio>
#include<algorithm>
#define X(o) ((o)<<1)
#define Y(o) ((o)<<1|1)
#define t (dis[i])
#define rg register
using namespace std;
int n,r[222],P,fast,slow,fastc,slowc;
const int maxd=420,maxm=23333,S=410,T=411,inf=233333333;
inline int gi() {
rg int x=0;
rg char ch=getchar();
while(ch>'9'||ch<'0')ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x;
}
int fir[maxd],nxt[maxm],dis[maxm],w[maxm],cost[maxm],id=1;
inline void add(int a,int b,int c,int d){
nxt[++id]=fir[a],fir[a]=id,dis[id]=b,w[id]=c,cost[id]=d;
if(c)add(b,a,0,-d);
}
inline void build(){
for(rg int i=1;i<=n;i++){
add(S,X(i),r[i],0),add(S,Y(i),inf,P);
add(Y(i),T,r[i],0);
add(X(i),X(i+1),inf,0);
if(i+fast<=n)add(X(i),Y(i+fast),inf,fastc);
if(i+slow<=n)add(X(i),Y(i+slow),inf,slowc);
}
}
inline bool spfa(int&F,int&C){
int que[maxd],pre[maxd],Dis[maxd];bool inque[maxd]={0};
rg int hd=1,tl=1;
que[tl++]=S,inque[S]=1;
for(rg int i=1;i<=Y(n);i++)Dis[i]=inf;Dis[T]=inf,Dis[S]=0;
while(hd^tl){
rg int now=que[hd];
for(rg int i=fir[now];i;i=nxt[i])
if(w[i]>0&&Dis[t]>Dis[now]+cost[i]){
Dis[t]=Dis[now]+cost[i],pre[t]=i;
if(!inque[t])que[tl++]=t,tl%=maxd,inque[t]=1;
}
hd=(hd+1)%maxd,inque[now]=0;
}
if(Dis[T]==inf)return 0;
rg int sum=inf;
for(int now=T,p;now^S;now=dis[p^1])p=pre[now],sum=min(sum,w[p]);
for(int now=T,p;now^S;now=dis[p^1])p=pre[now],w[p]-=sum,w[p^1]+=sum,C+=cost[p]*sum;
F+=sum;
return 1;
}
inline int mincost(int Flow=0,int Cost=0){
while(spfa(Flow,Cost));return Cost;
}
int main(){
n=gi();
for(rg int i=1;i<=n;i++)r[i]=gi();
P=gi(),fast=gi(),fastc=gi(),slow=gi(),slowc=gi();
build();
printf("%d\n",mincost());
return 0;
}
最长k可重区间集
直接看我link部分吧。。
// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cstring>
#define il inline
#define rg register
#define vd void
#define sta static
typedef long long ll;
il int gi(){
rg int x=0,f=1;rg char ch=getchar();
while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int maxn=501,maxN=1100,S=0,T=maxN-1,maxm=((1001+501)<<1)+233;
int l[maxn],r[maxn],num[maxn<<1];
int fir[maxN],dis[maxm],nxt[maxm],w[maxm],cost[maxm],id=1;
il vd link(const int&x,const int&y,const int&_w,const int&_c){nxt[++id]=fir[x],fir[x]=id,dis[id]=y,w[id]=_w,cost[id]=_c;}
il vd Link(int x,int y,int _w,int _c){link(x,y,_w,_c),link(y,x,0,-_c);}
il bool SPFA(int&c){
sta int que[maxN],hd,tl,dist[maxN],lst[maxN];
sta bool inque[maxN]={0};
memset(dist,63,sizeof dist);memset(lst,0,sizeof lst);
hd=tl=0;que[tl++]=S;inque[S]=1;dist[S]=0;
while(hd^tl){
sta int x;x=que[hd];
for(rg int i=fir[x];i;i=nxt[i])
if(dist[x]+cost[i]<dist[dis[i]]&&w[i]){
dist[dis[i]]=dist[x]+cost[i];lst[dis[i]]=i;
if(!inque[dis[i]])inque[dis[i]]=1,que[tl++]=dis[i],tl%=maxN;
}
++hd;hd%=maxN;inque[x]=0;
}
if(lst[T]==0)return 0;
int flow=233333333;
for(rg int i=lst[T];i;i=lst[dis[i^1]])flow=std::min(flow,w[i]);
for(rg int i=lst[T];i;i=lst[dis[i^1]])c+=cost[i]*flow,w[i]-=flow,w[i^1]+=flow;
return 1;
}
int main(){
int n=gi(),k=gi(),p;
for(rg int i=1;i<=n;++i){
l[i]=gi(),r[i]=gi();
num[++num[0]]=l[i],num[++num[0]]=r[i];
}
std::sort(num+1,num+2*n+1);
p=std::unique(num+1,num+2*n+1)-num-1;
for(rg int i=1;i<=n;++i)l[i]=std::lower_bound(num+1,num+p+1,l[i])-num,r[i]=std::lower_bound(num+1,num+p+1,r[i])-num;
for(rg int i=0;i<p;++i)Link(i,i+1,k,0);
for(rg int i=1;i<=n;++i)Link(l[i],r[i],1,-(num[r[i]]-num[l[i]]));
Link(p,T,k,0);
int c=0;while(SPFA(c));
printf("%d\n",-c);
return 0;
}
最长k可重线段集
与上道题一毛一样,特判与y轴平行的线段。
// It is made by XZZ
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define il inline
#define rg register
#define vd void
#define sta static
#define int long long
il int gi(){
rg int x=0,f=1;rg char ch=getchar();
while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int maxn=501,maxN=1100,S=0,T=maxN-1,maxm=((1001+501)<<1)+233;
int l[maxn],r[maxn],len[maxn],num[maxn<<1];
int fir[maxN],dis[maxm],nxt[maxm],w[maxm],cost[maxm],id=1;
il vd link(const int&x,const int&y,const int&_w,const int&_c){nxt[++id]=fir[x],fir[x]=id,dis[id]=y,w[id]=_w,cost[id]=_c;}
il vd Link(int x,int y,int _w,int _c){link(x,y,_w,_c),link(y,x,0,-_c);}
il bool SPFA(int&c){
sta int que[maxN],hd,tl,dist[maxN],lst[maxN];
sta bool inque[maxN]={0};
memset(dist,63,sizeof dist);memset(lst,0,sizeof lst);
hd=tl=0;que[tl++]=S;inque[S]=1;dist[S]=0;
while(hd^tl){
sta int x;x=que[hd];
for(rg int i=fir[x];i;i=nxt[i])
if(dist[x]+cost[i]<dist[dis[i]]&&w[i]){
dist[dis[i]]=dist[x]+cost[i];lst[dis[i]]=i;
if(!inque[dis[i]])inque[dis[i]]=1,que[tl++]=dis[i],tl%=maxN;
}
++hd;hd%=maxN;inque[x]=0;
}
if(lst[T]==0)return 0;
int flow=233333333;
for(rg int i=lst[T];i;i=lst[dis[i^1]])
flow=std::min(flow,w[i]);
for(rg int i=lst[T];i;i=lst[dis[i^1]])c+=cost[i]*flow,w[i]-=flow,w[i^1]+=flow;
return 1;
}
main(){
int n=gi(),k=gi(),p;
for(rg int i=1;i<=n;++i){
sta int x1,x2,y1,y2;
x1=gi(),y1=gi(),x2=gi(),y2=gi();len[i]=(int)(sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)));
if(x1>x2)std::swap(x1,x2),std::swap(y1,y2);
x1<<=1,x2<<=1;x1==x2?++x2:++x1;
l[i]=x1,r[i]=x2;
num[++num[0]]=l[i],num[++num[0]]=r[i];
}
std::sort(num+1,num+2*n+1);
p=std::unique(num+1,num+2*n+1)-num-1;
for(rg int i=1;i<=n;++i)l[i]=std::lower_bound(num+1,num+p+1,l[i])-num,r[i]=std::lower_bound(num+1,num+p+1,r[i])-num;
for(rg int i=0;i<p;++i)Link(i,i+1,k,0);
for(rg int i=1;i<=n;++i)Link(l[i],r[i],1,-len[i]);
Link(p,T,k,0);
int c=0;while(SPFA(c));
printf("%lld\n",-c);
return 0;
}
博主是蒟蒻,有问题请指出,谢谢!
本博客中博文均为原创,未经博主允许请勿随意转载,谢谢。
本博客中博文均为原创,未经博主允许请勿随意转载,谢谢。