const int maxn = 50000+50;
const int maxm = 200000+200;
#define Ci const int &
int n,m,s,t;
struct edge{
int u,v,n,flow;
I edge(Ci _u=0,Ci _v=0,Ci _n=0,Ci _flow=0):u(_u),v(_v),n(_n),flow(_flow){}
}e[maxm];
int cnt=1,head[maxn],cur[maxn];
I void add(Ci u,Ci v,Ci flow){
e[++cnt]=edge(u,v,head[u],flow),head[u]=cnt;
e[++cnt]=edge(v,u,head[v],0),head[v]=cnt;
}
int dep[maxn];
I bool bfs(){
queue<int>q;
memset(dep,0,sizeof dep);
memcpy(cur,head,sizeof(head));
dep[s]=1,q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
for(int ee=head[u],v;v=e[ee].v,ee;ee=e[ee].n)
if(e[ee].flow&&dep[v]==0)
dep[v]=dep[u]+1,q.push(v);
}
return dep[t];
}
int dfs(int u,int limit){
if(limit==0||u==t)return limit;
int flow=0,f;
for(int ee=cur[u],v;cur[u]=ee,v=e[ee].v,ee;ee=e[ee].n)
if(dep[v]==dep[u]+1&&(f=dfs(v,min(limit,e[ee].flow)))){
flow+=f;
limit-=f;
e[ee].flow-=f;
e[ee^1].flow+=f;
if(!limit)break;
}
return flow;
}
I int dinic(){
int ans=0;
while(bfs())
ans+=dfs(s,inf);
return ans;
}
signed main(){
read(n),read(m),read(s),read(t);
int u,v,f;
FOR(i,1,m)
read(u),read(v),read(f),
add(u,v,f);
write(dinic());
flush();
return 0;
}
int tot,s,t;
const int maxn = 50000+50;
const int maxm = 200000+200;
#define ci const int &
struct edge{
int u,v,f,n;
I edge(ci uu =0,ci vv=0,ci ff=0,ci nn=0):u(uu),v(vv),f(ff),n(nn){}
}e[maxm];
int cnt=1,head[maxn],cur[maxn],gap[maxn],dis[maxn];
I void add(ci u,ci v,ci f){
e[++cnt]=edge(u,v,f,head[u]),head[u]=cnt;
e[++cnt]=edge(v,u,0,head[v]),head[v]=cnt;
}
I void bfs(){
// memset(dis,0,sizeof dis);
// memset(gap,0,sizeof gap);
queue<int>q;q.push(t),gap[dis[t]=1]++;
while(!q.empty()){
int u=q.front();q.pop();
for(int ee=head[u],v;v=e[ee].v,ee;ee=e[ee].n)
if(!dis[v])gap[dis[v]=dis[u]+1]++,q.push(v);
}
}
int dfs(ci u,ci flow){
if(u==t)return flow;
int us=0,f;
for(int ee=cur[u],v;cur[u]=ee,v=e[ee].v,ee;ee=e[ee].n)
if(dis[v]==dis[u]-1){
if(f=dfs(v,min(flow-us,e[ee].f)))
e[ee].f-=f,e[ee^1].f+=f,us+=f;
if(us==flow)return flow;
}
(--gap[dis[u]])?(++gap[++dis[u]]):dis[s]=tot+1;
return us;
}
I int isap(){
int ans=0;
bfs();
while(dis[s]<=tot+1)
memcpy(cur,head,sizeof head),
ans+=dfs(s,inf);
return ans;
}
int n,m;
signed main(){
int u,v,f;
read(n),read(m),read(s),read(t);
tot=n;
FOR(i,1,m)read(u),read(v),read(f),add(u,v,f);
write(isap());
flush();
return 0;
}
const int maxn = 50000+500;
const int maxm = 200000+2000;
#define ci const int &
struct edge{
int u,v,f,w,n;
I edge(ci uu=0,ci vv=0,ci ff=0,ci ww=0,ci nn=0):u(uu),v(vv),f(ff),w(ww),n(nn){}
}e[maxm];
int dis[maxn],vis[maxn],cur[maxn],head[maxn],cnt=1,n,m,s,t;
int cost=0,flow=0;
I void add(ci u,ci v,ci f,ci w){
e[++cnt]=edge(u,v,f,w,head[u]),head[u]=cnt;
e[++cnt]=edge(v,u,0,-w,head[v]),head[v]=cnt;
}
I bool spfa(ci s,ci t){
memset(vis,0,sizeof vis);
memset(dis,0x3f,sizeof dis);
deque<int>q;q.push_front(t);
vis[t]=1,dis[t]=0;
while(!q.empty()){
int u=q.front();q.pop_front();
for(int ee=head[u],v;v=e[ee].v,ee;ee=e[ee].n)
if(e[ee^1].f>0&&dis[v]>dis[u]-e[ee].w){
dis[v]=dis[u]-e[ee].w;
if(!vis[v])vis[v]=1,(!q.empty()&&dis[q.front()]>dis[v])?
q.push_front(v):
q.push_back(v);
}
vis[u]=0;
}
return dis[s]==0x3f3f3f3f?0:1;
}
int dfs(ci u,ci ff){
if(u==t)return vis[t]=1,ff;
int us=0,f;vis[u]=1;
for(int ee=cur[u],v;cur[u]=ee,v=e[ee].v,ee;ee=e[ee].n)
if(vis[v]==0&&e[ee].f>0&&dis[u]-e[ee].w==dis[v]){
if((f=dfs(v,min(e[ee].f,ff-us)))>0)
cost+=f*e[ee].w,e[ee].f-=f,e[ee^1].f+=f,us+=f;
if(us==ff)break;
}
return us;
}
I void cost_flow(){
while(spfa(s,t)){
vis[t]=1;
while(vis[t]){
memcpy(cur,head,sizeof head);
memset(vis,0,sizeof vis);
flow+=dfs(s,inf);
}
}
}
signed main(){
read(n),read(m),read(s),read(t);
int u,v,f,w;
FOR(i,1,m)
read(u),read(v),read(f),read(w),
add(u,v,f,w);
cost_flow();
write(flow),pc(' '),write(cost);
flush();
return 0;
}
]]>const int maxn = 1000000+100;
int n,m,k,len,ans;
int num[maxn],cnt[maxn],a[maxn];
struct query{
int l,r,in,id;
I bool operator <(const query &a)const
{return (in^a.in)?in<a.in:((in&1)?r<a.r:r>a.r);}
}q[maxn];
signed main(){
read(n);
int QAQ=pow(n,0.6);
len=QAQ*QAQ*QAQ;
for(R int *S=a,*T=a+n;S!=T;)read(*++S);
read(m);
int x,y;
FOR(i,1,m)
read(q[i].l),read(q[i].r),
q[i].in=(q[i].l-1)/len+1,
q[i].id=i;
sort(q+1,q+1+m);
int l=1,r=0;
FOR(i,1,m){
int x=q[i].l,y=q[i].r;
while(l<x)ans-=(!--cnt[a[l++]]);
while(l>x)ans+=(!cnt[a[--l]]++);
while(r<y)ans+=(!cnt[a[++r]]++);
while(r>y)ans-=(!--cnt[a[r--]]);
num[q[i].id]=ans;
}
for(R int *S=num,*T=num+m;S!=T;)write(*++S),pc('\n');
flush();
return 0;
}
const int maxn=2*1e6+10;
int n,m,a[maxn],in[maxn];
struct Query{
int x,y,pre,id;
}Q[maxn];
struct Change{
int pos,val;
}C[maxn];
int Qnum=0,Cnum=0;
int cnt[maxn],ans=0,base,out[maxn];
I int cmp(const Query &a,const Query &b){
if(a.x!=b.x)return in[a.x]<in[b.x];
if(a.y!=b.x)return in[a.y]<in[b.y];
return a.pre<b.pre;
}
I void work(int now,int i){
if(C[now].pos>=Q[i].x&&C[now].pos<=Q[i].y){
if(--cnt[a[C[now].pos]]==0)ans--;
if(++cnt[C[now].val]==1)ans++;
}
swap(C[now].val,a[C[now].pos]);
}
I void MoQueue(){
int l=1,r=0,now=0;
FOR(i,1,Qnum){
while(l<Q[i].x)ans-=!--cnt[a[l++]];
while(l>Q[i].x)ans+=!cnt[a[--l]]++;
while(r<Q[i].y)ans+=!cnt[a[++r]]++;
while(r>Q[i].y)ans-=!--cnt[a[r--]];
while(now<Q[i].pre)work(++now,i);
while(now>Q[i].pre)work(now--,i);
out[Q[i].id]=ans;
}
FOR(i,1,Qnum)
write(out[i]),pc('\n');
}
signed main(){
read(n),read(m);
base=pow(n,(double)2/(double)3);
FOR(i,1,n)read(a[i]),in[i]=(i-1)/base+1;
while(m--){
if(Read()){
read(Q[++Qnum].x),
read(Q[Qnum].y),
Q[Qnum].pre=Cnum,
Q[Qnum].id=Qnum;
}else{
read(C[++Cnum].pos);
read(C[Cnum].val);
}
}
sort(Q+1,Q+Qnum+1,cmp);
MoQueue();
flush();
return 0;
}
//a,cnt,first,last,ans,belong,inp,vis,ncnt,l,r,now,size,bnum莫队相关
int a[maxn],cnt[maxn],first[maxn],last[maxn];
int ans[maxn],belong[maxn],inp[maxn],vis[maxn];
int ord[maxn],val[maxn],head[maxn],dep[maxn];
int fa[maxn][21],ecnt,ncnt,l=1,r,now,len,bnum,n,m;
// ord Euler-pos first Euler->begin last Euler->end;
struct edge{
int v,n;
I edge(const int &vv=0,const int & nn=0):v(vv),n(nn){}
}e[maxn];
void add(int u,int v){
e[++ecnt]=edge(v,head[u]),head[u]=ecnt;
e[++ecnt]=edge(u,head[v]),head[v]=ecnt;
}
void dfs(int u){
ord[++ncnt]=u;
first[u]=ncnt;
for(int ee=head[u],v;v=e[ee].v,ee;ee=e[ee].n)
if(v!=fa[u][0]){
dep[v]=dep[u]+1;
fa[v][0]=u;
for(int i=1;(1<<i)<=dep[v];++i)fa[v][i]=fa[fa[v][i-1]][i-1];
dfs(v);
}
ord[++ncnt]=u;
last[u]=ncnt;
}
int get_lca(int u,int v){
if(dep[u]<dep[v])swap(u,v);
for(int i=20;i+1;--i)
if(dep[u]-(1<<i)>=dep[v])u=fa[u][i];
if(u==v)return u;
for(int i=20;i+1;--i)
if(fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
struct query{
int l,r,lca,id;
}q[maxn];
int cmp(const query &a,const query &b){
return (belong[a.l]^belong[b.l])?(belong[a.l]<belong[b.l]):((belong[a.l]&1)?a.r<b.r:a.r>b.r);
}
I void work(int pos){
vis[pos]?
now-=!--cnt[val[pos]]:
now+=!cnt[val[pos]]++;
vis[pos]^=1;
}
signed main(){
read(n),read(m);
FOR(i,1,n)read(val[i]),inp[i]=val[i];
sort(inp+1,inp+1+n);
int tot=unique(inp+1,inp+1+n)-inp-1;
FOR(i,1,n)
val[i]=lower_bound(inp+1,inp+tot+1,val[i])-inp;
int x,y;
FOR(i,1,n-1)read(x),read(y),add(x,y);
dep[1]=1;dfs(1);
len=sqrt(ncnt),bnum=ceil((double)ncnt/len);
FOR(i,1,bnum)
for(int j=len*(i-1)+1;j<=i*len;++j)
belong[j]=i;
FOR(i,1,m){
int x,y,lca;
read(x),read(y),lca=get_lca(x,y);
if(first[x]>first[y])swap(x,y);
if(x==lca){
q[i].l=first[x];
q[i].r=first[y];
}else{
q[i].l=last[x];
q[i].r=first[y];
q[i].lca=lca;
}
q[i].id=i;
}
sort(q+1,q+1+m,cmp);
FOR(i,1,m){
int ql=q[i].l,qr=q[i].r,lca=q[i].lca;
while(l<ql)work(ord[l++]);
while(l>ql)work(ord[--l]);
while(r<qr)work(ord[++r]);
while(r>qr)work(ord[r--]);
if(lca)work(lca);
ans[q[i].id]=now;
if(lca)work(lca);
}
FOR(i,1,m)write(ans[i]),pc('\n');
flush();
return 0;
}
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define maxn 100100
#define maxb 5050
#define ll long long
int aa[maxn], typ[maxn], cnt[maxn], cnt2[maxn], belong[maxn], lb[maxn], rb[maxn], inp[maxn];
ll ans[maxn];
struct query {
int l, r, id;
} q[maxn];
int n, m, size, bnum;
#define isdigit(x) ((x) >= '0' && (x) <= '9')
inline int read() {
int res = 0;
char c = getchar();
while(!isdigit(c)) c = getchar();
while(isdigit(c)) res = (res << 1) + (res << 3) + (c ^ 48), c = getchar();
return res;
}
int cmp(query a, query b) {
return (belong[a.l] ^ belong[b.l]) ? belong[a.l] < belong[b.l] : a.r < b.r;
}
int main() {
n = read(), m = read();
size = sqrt(n);
bnum = ceil((double) n / size);
for(int i = 1; i <= bnum; ++i) {
lb[i] = size * (i - 1) + 1;
rb[i] = size * i;
for(int j = lb[i]; j <= rb[i]; ++j) belong[j] = i;
}
rb[bnum] = n;
for(int i = 1; i <= n; ++i) inp[i] = aa[i] = read();
sort(inp + 1, inp + n + 1);
int tot = unique(inp + 1, inp + n + 1) - inp - 1;
for(int i = 1; i <= n; ++i) typ[i] = lower_bound(inp + 1, inp + tot + 1, aa[i]) - inp;
for(int i = 1; i <= m; ++i) {
q[i].l = read(), q[i].r = read();
q[i].id = i;
}
sort(q + 1, q + m + 1, cmp);
int i = 1;
for(int k = 0; k <= bnum; ++k) {
int l = rb[k] + 1, r = rb[k];
ll now = 0;
memset(cnt, 0, sizeof(cnt));
for( ; belong[q[i].l] == k; ++i) {
int ql = q[i].l, qr = q[i].r;
ll tmp;
if(belong[ql] == belong[qr]) {
tmp = 0;
for(int j = ql; j <= qr; ++j) cnt2[typ[j]] = 0;
for(int j = ql; j <= qr; ++j) {
++cnt2[typ[j]]; tmp = max(tmp, 1ll * cnt2[typ[j]] * aa[j]);
}
ans[q[i].id] = tmp;
continue;
}
while(r < qr) {
++r; ++cnt[typ[r]]; now = max(now, 1ll * cnt[typ[r]] * aa[r]);
}
tmp = now;
while(l > ql){
--l; ++cnt[typ[l]]; now = max(now, 1ll * cnt[typ[l]] * aa[l]);
}
ans[q[i].id] = now;
while(l < rb[k] + 1) {
--cnt[typ[l]];
l++;
}
now = tmp;
}
}
for(int i = 1; i <= m; ++i) printf("%lld\n", ans[i]);
return 0;
}
]]>求多边形的重心。
对于一个平面多边形可以被分成个有个的简单图形,这些简单图形的重心为,面积为,那么这个平面多边形的重心点坐标为
然后把图形拆分为多个三角形就好了。
参考链接
精度有问题(完)
]]>给出条线段判断有多少个交点,(假如多个线段交于一点应重复计数)。
数据范围很小枚举即可。
关于判断是否相交,先判断两条直线是否有交点,然后用叉积判断线段的两个的端点是否跨立另一条线段。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <cmath>
using namespace std;
#define I inline
#define R register
#define inf 1073742823
#define FOR(i,begin,end) for(R int i=begin;i<=end;++i)
#define ROF(i,begin,end) for(R int i=begin;i>=end;--i)
const double eps=1e-10;
const double pi=acos(-1.0);
I int dcmp(double x)
{ if(fabs(x)<eps)return 0;
else return x<0?-1:1;}
#define P point
#define PP const P &
struct point{
double x,y;
I P(const double &_x=0,const double &_y=0):x(_x),y(_y){}
I bool operator ==(PP a)const{return dcmp(x-a.x)==0&&dcmp(y-a.y)==0;}
I bool operator<(PP a)const{return x<a.x||(x==a.x&&y<a.y);}
I P operator+(PP a)const{return P(x+a.x,y+a.y);}
I P operator-(PP a)const{return P(x-a.x,y-a.y);}
I P operator*(const double a)const{return P(x*a,y*a);}
I P operator/(const double a)const{return P(x/a,y/a);}
I P operator*(PP a)const{return P(x*a.x-y*a.y,x*a.y+y*a.x);}
I double len()const{return sqrt(x*x+y*y);}
I double len2()const{return x*x+y*y;}
I P rotate(const double theta)const{return P(x,y)*P(cos(theta),sin(theta));}
I double operator|(PP a)const{return x*a.x+y*a.y;}
I double operator&(PP a)const{return x*a.y-y*a.x;}
I P norm(){return *this/len();}
I double angle(PP a)const{return *this|a/len()/a.len();}
};
typedef point vec;
const int maxn=110;
struct line{
P a,b;
}L[maxn];
I int D_pos(PP q,const line A){
vec k1=q-A.a,k2=A.b-A.a;
return dcmp(k1&k2);
}
I bool across(const line &a,const line &b){
int ans1=D_pos(a.a,b);
int ans2=D_pos(a.b,b);
int ans3=D_pos(b.a,a);
int ans4=D_pos(b.b,a);
if((ans1&ans2&ans3&ans4)==0)return 1;
if(ans1!=ans2&&ans3!=ans4)
return 1;
else return 0;
}
I bool check(const line &a,const line & b){
vec k1=a.b-a.a,k2=b.b-b.a;
if(dcmp(k1&k2)==0)return 0;
else return across(a,b);
}
signed main(){
int n;
while(scanf("%d",&n)&&n!=0){
memset(L,0,sizeof L);
FOR(i,1,n)
scanf("%lf%lf%lf%lf",&L[i].a.x,&L[i].a.y,&L[i].b.x,&L[i].b.y);
int ans=0;
FOR(i,1,n)
FOR(j,i+1,n)
ans+=check(L[i],L[j]);
printf("%d\n",ans);
}
return 0;
}
]]>网络流模板
个人喜欢用dinic跑非一次性建边的网络流,用isap跑一次性建边的网络流,用zkw跑费用流,至于HLPP我还不会
当然网络流还是要靠建图。
显然的一个二分图匹配问题,还要输出方案;
我们考虑建图,首先一个飞行员只能匹配一个飞行员,所以我们从S向一类飞行员连边,从另一类飞行员向T连边,边权为1,然后对于能匹配的飞行员我们连接1或者inf的边(本体都可),完成建图。
关于输出方案:考虑残量网络上的反向边发生流量改变即可。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <cmath>
using namespace std;
#define I inline
#define R register
#define inf 1073742823
#define FOR(i,begin,end) for(R int i=begin;i<=end;++i)
#define ROF(i,begin,end) for(R int i=begin;i>=end;--i)
#include<queue>
namespace IO{
char buf[1<<21],*pa=buf,*pb=buf;
char buffer[1<<21];int p1=-1;const int p2=(1<<21)-1;
I char gc(){return pa==pb&&(pb=(pa=buf)+fread(buf,1,1<<21,stdin),pa==pb)?EOF:*pa++;}
template<class T>I void read(T &x){
x=0;R int y=0;R char ch=gc();
for(;!isdigit(ch);ch=gc())y=ch=='-';
for(;isdigit(ch);ch=gc())x=x*10+(ch^48);
(y)&&(x=-x);return;}
I void flush(){fwrite(buffer,1,p1+1,stdout);p1=-1;return;}
I void pc(int ch){if(p1==p2)flush();buffer[++p1]=ch;return;}
template<class T>I void write(T x){
static char buf[20];static int len =-1;
if(x>=0){do buf[++len]=(x%10)^48,x/=10;while(x);}
else{pc('-');do buf[++len]=(-(x%10))^48,x/=10;while(x);}
while(len>=0)pc(buf[len--]);
return;}
}
using namespace IO;
int tot,s,t;
const int maxn = 50000+50;
const int maxm = 200000+200;
#define ci const int &
struct edge{
int u,v,f,n;
I edge(ci uu =0,ci vv=0,ci ff=0,ci nn=0):u(uu),v(vv),f(ff),n(nn){}
}e[maxm];
int cnt=1,head[maxn],cur[maxn],gap[maxn],dis[maxn],mxflow=0;
I void add(ci u,ci v,ci f){
e[++cnt]=edge(u,v,f,head[u]),head[u]=cnt;
e[++cnt]=edge(v,u,0,head[v]),head[v]=cnt;
}
I void bfs(){
queue<int>q;q.push(t),gap[dis[t]=1]++;
while(!q.empty()){
int u=q.front();q.pop();
for(int ee=head[u],v;v=e[ee].v,ee;ee=e[ee].n)
if(!dis[v])gap[dis[v]=dis[u]+1]++,q.push(v);
}
}
int dfs(ci u,ci flow){
if(u==t&&((mxflow+=flow)||1))return flow;
int us=0,f;
for(int ee=cur[u],v;cur[u]=ee,v=e[ee].v,ee;ee=e[ee].n)
if(dis[v]==dis[u]-1){
if(f=dfs(v,min(flow-us,e[ee].f)))
e[ee].f-=f,e[ee^1].f+=f,us+=f;
if(us==flow)return flow;
}
(--gap[dis[u]])?(++gap[++dis[u]]):dis[s]=tot+1;
return us;
}
I int isap(){
bfs();
while(dis[s]<=tot+1)
memcpy(cur,head,sizeof head),
dfs(s,inf);
return mxflow;
}
int n,m;
int fa[maxn];
I int getf(int x){return x==fa[x]?x:fa[x]=getf(fa[x]);}
I void output(int x){
write(x),pc(' ');
for(int ee=head[x],v;v=e[ee].v,ee;ee=e[ee].n)
if(ee>=4*n+2)
if(e[ee^1].f!=0&&v>n)
output(v-n);
return;
}
signed main(){
int x,y;
read(n),read(m);
s=0,t=2*n+1,tot=2*n+2;
FOR(i,1,n)
add(s,i,1),
add(i+n,t,1);
// cnt = 4n+1;
FOR(i,1,m)
read(x),read(y),
add(x,y+n,1);
// cnt = 4n + 2m + 1;
int ans = n - isap();
FOR(i,1,n)fa[i]=i;
for(int ee=4*n+2;ee<=cnt;ee+=2)
if(e[ee^1].f!=0)
fa[getf(e[ee].v-n)]=getf(e[ee].u);
FOR(i,1,n)
if(getf(i)==i)
output(i),pc('\n');
write(ans);
flush();
return 0;
}
仍然是一个类似二分图的问题,也要输出方案。
我们考虑从S向每个单位连接流量为的边,表示这个单位的人数,从每个餐桌向T连接流量为的边,表示餐桌可以容纳的人数,对于所有的单位向所有的餐桌连一条流量为1的边,表示同一个单位来的代表不在同一个餐桌就餐,建图完成。输出方案与上题同理。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <vector>
using namespace std;
#define I inline
#define R register
#define inf 1073742823
#define FOR(i,begin,end) for(R int i=begin;i<=end;++i)
#define ROF(i,begin,end) for(R int i=begin;i>=end;--i)
#include<queue>
namespace IO{
char buf[1<<21],*pa=buf,*pb=buf;
char buffer[1<<21];int p1=-1;const int p2=(1<<21)-1;
I char gc(){return pa==pb&&(pb=(pa=buf)+fread(buf,1,1<<21,stdin),pa==pb)?EOF:*pa++;}
template<class T>I void read(T &x){
x=0;R int y=0;R char ch=gc();
for(;!isdigit(ch);ch=gc())y=ch=='-';
for(;isdigit(ch);ch=gc())x=x*10+(ch^48);
(y)&&(x=-x);return;}
I void flush(){fwrite(buffer,1,p1+1,stdout);p1=-1;return;}
I void pc(int ch){if(p1==p2)flush();buffer[++p1]=ch;return;}
template<class T>I void write(T x){
static char buf[20];static int len =-1;
if(x>=0){do buf[++len]=(x%10)^48,x/=10;while(x);}
else{pc('-');do buf[++len]=(-(x%10))^48,x/=10;while(x);}
while(len>=0)pc(buf[len--]);
return;}
}
using namespace IO;
int s,t,tot;
const int maxn = 50000+50;
const int maxm = 200000+200;
#define ci const int &
struct edge{
int u,v,f,n;
I edge(ci uu =0,ci vv=0,ci ff=0,ci nn=0):u(uu),v(vv),f(ff),n(nn){}
}e[maxm];
int cnt=1,head[maxn],cur[maxn],gap[maxn],dis[maxn],mxflow=0;
I void add(ci u,ci v,ci f){
e[++cnt]=edge(u,v,f,head[u]),head[u]=cnt;
e[++cnt]=edge(v,u,0,head[v]),head[v]=cnt;
}
I void bfs(){
queue<int>q;q.push(t),gap[dis[t]=1]++;
while(!q.empty()){
int u=q.front();q.pop();
for(int ee=head[u],v;v=e[ee].v,ee;ee=e[ee].n)
if(!dis[v])gap[dis[v]=dis[u]+1]++,q.push(v);
}
}
int dfs(ci u,ci flow){
if(u==t&&((mxflow+=flow)||1))return flow;
int us=0,f;
for(int ee=cur[u],v;cur[u]=ee,v=e[ee].v,ee;ee=e[ee].n)
if(dis[v]==dis[u]-1){
if(f=dfs(v,min(flow-us,e[ee].f)))
e[ee].f-=f,e[ee^1].f+=f,us+=f;
if(us==flow)return flow;
}
(--gap[dis[u]])?(++gap[++dis[u]]):dis[s]=tot+1;
return us;
}
int n,m,x,sum;
int rr[maxn],cc[maxn];
vector<int>ans[maxn];
signed main(){
read(n),read(m);
s=0,t=n+m+1;
tot=t;
FOR(i,1,n)
read(rr[i]),sum+=rr[i],
add(s,i,rr[i]);
FOR(i,1,m)
read(cc[i]),
add(i+n,t,cc[i]);
FOR(i,1,n)
FOR(j,1,m)
add(i,j+n,1);
while(dis[s]<=tot+1)memcpy(cur,head,sizeof(head)),dfs(s,inf);
if(mxflow!=sum){
puts("0");
return 0;
}
write(1),pc('\n');
for(int ee=2*(n+m+1);ee<=cnt;ee+=2)
if(e[ee^1].f!=0)
ans[e[ee].u].push_back(e[ee].v);
FOR(i,1,n){
for(auto k:ans[i])
write(k-n),pc(' ');
pc('\n');
}
flush();
return 0;
}
题目渐渐有了难度,模板题洛谷也给了提示
我们考虑拆点,把一个点拆成两个点,第一个拆点表示出边,第二个拆点表示入边,我们把S向第一个拆点连一条流量为1的边,表示这个点的出度最大为1,把第二个拆点向T连接一条流量为1的边,表示这个点的最大入度为1,然后我们连接原图中的边,流量为1,表示存在路径,建图完成。
我们对原图跑一个最大流,显然就是匹配数,所以n-匹配数即为答案,关于路径输出和路径起点,与第一题同理。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <cmath>
using namespace std;
#define I inline
#define R register
#define inf 1073742823
#define FOR(i,begin,end) for(R int i=begin;i<=end;++i)
#define ROF(i,begin,end) for(R int i=begin;i>=end;--i)
#include<queue>
namespace IO{
char buf[1<<21],*pa=buf,*pb=buf;
char buffer[1<<21];int p1=-1;const int p2=(1<<21)-1;
I char gc(){return pa==pb&&(pb=(pa=buf)+fread(buf,1,1<<21,stdin),pa==pb)?EOF:*pa++;}
template<class T>I void read(T &x){
x=0;R int y=0;R char ch=gc();
for(;!isdigit(ch);ch=gc())y=ch=='-';
for(;isdigit(ch);ch=gc())x=x*10+(ch^48);
(y)&&(x=-x);return;}
I void flush(){fwrite(buffer,1,p1+1,stdout);p1=-1;return;}
I void pc(int ch){if(p1==p2)flush();buffer[++p1]=ch;return;}
template<class T>I void write(T x){
static char buf[20];static int len =-1;
if(x>=0){do buf[++len]=(x%10)^48,x/=10;while(x);}
else{pc('-');do buf[++len]=(-(x%10))^48,x/=10;while(x);}
while(len>=0)pc(buf[len--]);
return;}
}
using namespace IO;
int tot,s,t;
const int maxn = 50000+50;
const int maxm = 200000+200;
#define ci const int &
struct edge{
int u,v,f,n;
I edge(ci uu =0,ci vv=0,ci ff=0,ci nn=0):u(uu),v(vv),f(ff),n(nn){}
}e[maxm];
int cnt=1,head[maxn],cur[maxn],gap[maxn],dis[maxn],mxflow=0;
I void add(ci u,ci v,ci f){
e[++cnt]=edge(u,v,f,head[u]),head[u]=cnt;
e[++cnt]=edge(v,u,0,head[v]),head[v]=cnt;
}
I void bfs(){
queue<int>q;q.push(t),gap[dis[t]=1]++;
while(!q.empty()){
int u=q.front();q.pop();
for(int ee=head[u],v;v=e[ee].v,ee;ee=e[ee].n)
if(!dis[v])gap[dis[v]=dis[u]+1]++,q.push(v);
}
}
int dfs(ci u,ci flow){
if(u==t&&((mxflow+=flow)||1))return flow;
int us=0,f;
for(int ee=cur[u],v;cur[u]=ee,v=e[ee].v,ee;ee=e[ee].n)
if(dis[v]==dis[u]-1){
if(f=dfs(v,min(flow-us,e[ee].f)))
e[ee].f-=f,e[ee^1].f+=f,us+=f;
if(us==flow)return flow;
}
(--gap[dis[u]])?(++gap[++dis[u]]):dis[s]=tot+1;
return us;
}
I int isap(){
bfs();
while(dis[s]<=tot+1)
memcpy(cur,head,sizeof head),
dfs(s,inf);
return mxflow;
}
int n,m;
int fa[maxn];
I int getf(int x){return x==fa[x]?x:fa[x]=getf(fa[x]);}
I void output(int x){
write(x),pc(' ');
for(int ee=head[x],v;v=e[ee].v,ee;ee=e[ee].n)
if(ee>=4*n+2)
if(e[ee^1].f!=0&&v>n)
output(v-n);
return;
}
signed main(){
int x,y;
read(n),read(m);
s=0,t=2*n+1,tot=2*n+2;
FOR(i,1,n)
add(s,i,1),
add(i+n,t,1);
// cnt = 4n+1;
FOR(i,1,m)
read(x),read(y),
add(x,y+n,1);
// cnt = 4n + 2m + 1;
int ans = n - isap();
FOR(i,1,n)fa[i]=i;
for(int ee=4*n+2;ee<=cnt;ee+=2)
if(e[ee^1].f!=0)
fa[getf(e[ee].v-n)]=getf(e[ee].u);
FOR(i,1,n)
if(getf(i)==i)
output(i),pc('\n');
write(ans);
flush();
return 0;
}
显然这是一个需要不断加边的网络流,我们将一个数向与他组成完全平方数的数的拆点连边,S向原数连边,拆点向T连边,跑网络流即可,与上一题思想相似。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <cmath>
using namespace std;
#define I inline
#define R register
#define inf 1073742823
#define FOR(i,begin,end) for(R int i=begin;i<=end;++i)
#define ROF(i,begin,end) for(R int i=begin;i>=end;--i)
namespace IO{
char buf[1<<21],*pa=buf,*pb=buf;
char buffer[1<<21];int p1=-1;const int p2=(1<<21)-1;
I char gc(){return pa==pb&&(pb=(pa=buf)+fread(buf,1,1<<21,stdin),pa==pb)?EOF:*pa++;}
template<class T>I void read(T &x){
x=0;R int y=0;R char ch=gc();
for(;!isdigit(ch);ch=gc())y=ch=='-';
for(;isdigit(ch);ch=gc())x=x*10+(ch^48);
(y)&&(x=-x);return;}
I void flush(){fwrite(buffer,1,p1+1,stdout);p1=-1;return;}
I void pc(int ch){if(p1==p2)flush();buffer[++p1]=ch;return;}
template<class T>I void write(T x){
static char buf[20];static int len =-1;
if(x>=0){do buf[++len]=(x%10)^48,x/=10;while(x);}
else{pc('-');do buf[++len]=(-(x%10))^48,x/=10;while(x);}
while(len>=0)pc(buf[len--]);
return;}
}
using namespace IO;
const int maxn = 50000+50;
const int maxm = 200000+200;
#define Ci const int &
int n,m,s,t;
struct edge{
int u,v,n,flow;
I edge(Ci _u=0,Ci _v=0,Ci _n=0,Ci _flow=0):u(_u),v(_v),n(_n),flow(_flow){}
}e[maxm];
int cnt=1,head[maxn],cur[maxn];
I void add(Ci u,Ci v,Ci flow){
e[++cnt]=edge(u,v,head[u],flow),head[u]=cnt;
e[++cnt]=edge(v,u,head[v],0),head[v]=cnt;
}
int dep[maxn],pre[maxn];
#include<queue>
I bool bfs(){
queue<int>q;
memset(dep,0,sizeof dep);
memcpy(cur,head,sizeof(head));
dep[s]=1,q.push(s);
while(!q.empty()){
int u=q.front();q.pop();
for(int ee=head[u],v;v=e[ee].v,ee;ee=e[ee].n)
if(e[ee].flow&&dep[v]==0)
dep[v]=dep[u]+1,q.push(v);
}
return dep[t];
}
int dfs(int u,int limit){
if(limit==0||u==t)return limit;
int flow=0,f;
for(int ee=cur[u],v;cur[u]=ee,v=e[ee].v,ee;ee=e[ee].n)
if(dep[v]==dep[u]+1&&(f=dfs(v,min(limit,e[ee].flow)))){
flow+=f;
limit-=f;
e[ee].flow-=f;
e[ee^1].flow+=f;
pre[u>>1]=v>>1;
if(!limit)break;
}
return flow;
}
I int dinic(){
int ans=0;
while(bfs())
ans+=dfs(s,inf);
return ans;
}
I bool check(int x){
int xx=sqrt(x);
return xx==x;
}
int top,now,sta[maxn],vis[maxn];
signed main(){
read(n);
s=maxn-10,t=maxn-9;
while(top<=n){
++now;
add(s,now<<1,1);
add((now<<1)|1,t,1);
for(int i=sqrt(now)+1;i*i<(now<<1);++i)
add((i*i-now)<<1,(now << 1)|1,1);
int flow=dinic();
if(!flow)
sta[++top]=now;
}
write(now-1),pc('\n');
FOR(i,1,n)
if(!vis[sta[i]]){
for(int u=sta[i];u&&u!=(t>>1);u=pre[u])
vis[u]=1,write(u),pc(' ');
pc('\n');
}
flush();
return 0;
}
第一问我们考虑直接DP;
第二问我们向原点和拆点连一条为1的边表示只能被选一次,然后对于DP值等于1的从源点S向其连边,流量为1,对于DP等于长度的,从其向汇点T连边,流量为1,表示路径可行性。
第三问在残量网络上加源点到1的边,假如最后一个数在最长上升子序列上,连接一条向汇点的边,还有原点向拆点连边,流量为inf,表示可以无限使用。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <cmath>
using namespace std;
#define I inline
#define R register
#define inf 1073742823
#define FOR(i,begin,end) for(R int i=begin;i<=end;++i)
#define ROF(i,begin,end) for(R int i=begin;i>=end;--i)
#include<queue>
namespace IO{
char buf[1<<21],*pa=buf,*pb=buf;
char buffer[1<<21];int p1=-1;const int p2=(1<<21)-1;
I char gc(){return pa==pb&&(pb=(pa=buf)+fread(buf,1,1<<21,stdin),pa==pb)?EOF:*pa++;}
template<class T>I void read(T &x){
x=0;R int y=0;R char ch=gc();
for(;!isdigit(ch);ch=gc())y=ch=='-';
for(;isdigit(ch);ch=gc())x=x*10+(ch^48);
(y)&&(x=-x);return;}
I void flush(){fwrite(buffer,1,p1+1,stdout);p1=-1;return;}
I void pc(int ch){if(p1==p2)flush();buffer[++p1]=ch;return;}
template<class T>I void write(T x){
static char buf[20];static int len =-1;
if(x>=0){do buf[++len]=(x%10)^48,x/=10;while(x);}
else{pc('-');do buf[++len]=(-(x%10))^48,x/=10;while(x);}
while(len>=0)pc(buf[len--]);
return;}
}
using namespace IO;
int tot,s,t;
const int maxn = 5000+50;
const int maxm = 200000+200;
#define ci const int &
struct edge{
int u,v,f,n;
I edge(ci uu =0,ci vv=0,ci ff=0,ci nn=0):u(uu),v(vv),f(ff),n(nn){}
}e[maxm];
int cnt=1,head[maxn],cur[maxn],gap[maxn],dis[maxn];
I void add(ci u,ci v,ci f){
e[++cnt]=edge(u,v,f,head[u]),head[u]=cnt;
e[++cnt]=edge(v,u,0,head[v]),head[v]=cnt;
}
I void bfs(){
memset(dis,0,sizeof dis);
memset(gap,0,sizeof gap);
queue<int>q;q.push(t),gap[dis[t]=1]++;
while(!q.empty()){
int u=q.front();q.pop();
for(int ee=head[u],v;v=e[ee].v,ee;ee=e[ee].n)
if(!dis[v])gap[dis[v]=dis[u]+1]++,q.push(v);
}
}
int dfs(ci u,ci flow){
if(u==t)return flow;
int us=0,f;
for(int ee=cur[u],v;cur[u]=ee,v=e[ee].v,ee;ee=e[ee].n)
if(dis[v]==dis[u]-1){
if(f=dfs(v,min(flow-us,e[ee].f)))
e[ee].f-=f,e[ee^1].f+=f,us+=f;
if(us==flow)return flow;
}
(--gap[dis[u]])?(++gap[++dis[u]]):dis[s]=tot+1;
return us;
}
I int isap(){
int ans=0;
bfs();
while(dis[s]<=tot+1)
memcpy(cur,head,sizeof head),
ans+=dfs(s,inf);
return ans;
}
int n,a[maxn],dp[maxn];
#define ls(i) (i<<1)
#define rs(i) (i<<1|1)
signed main(){
read(n);
FOR(i,1,n)read(a[i]),dp[i]=1;
FOR(i,1,n)
FOR(j,1,i-1)
if(a[j]<=a[i])dp[i]=max(dp[i],dp[j]+1);
int len;FOR(i,1,n)len=max(len,dp[i]);
write(len),pc('\n');
s=0,t=1;tot=2+2*n;
FOR(i,1,n)if(dp[i]==1)add(s,ls(i),1);
FOR(i,1,n)if(dp[i]==len)add(rs(i),t,1);
FOR(i,1,n)add(ls(i),rs(i),1);
FOR(i,1,n)
FOR(j,1,i-1)
if(a[j]<=a[i]&&dp[j]+1==dp[i])
add(rs(j),ls(i),1);
int last;
write(last=isap()),pc('\n');
add(ls(1),rs(1),inf),add(s,ls(1),inf);
if(dp[n]==len)add(ls(n),rs(n),inf),add(rs(n),t,inf);
write(last+isap()),pc('\n');
flush();
return 0;
}
最大权闭合图问题,考虑如下建图方案,由源点S向每个实验仪器连边,流量为费用,由实验向汇点T连边,流量为获利,由实验仪器向对应的实验连边,流量为inf,对所建图求最小割,即最小割为ans,则最后答案为总实验的获利-ans;
(若割边是源点到仪器则表示仪器不选用,若割边为实验则代表实验不选用)
(之前写的忘了保存挂了,我哭了,嘤嘤嘤)
我们考虑如下建图方式
将每一天拆为两个点,分别表示旧餐巾和新餐巾。
(消耗=产生=r)(不特别说明,费用为零,流量为inf)
由源点向每天的旧餐巾连接一条流量为产生的边,表示每天产生的旧餐巾。
由每天的新餐巾向汇点连接一条流量为消耗的边,表示每天消耗的新餐巾。
由源点向每天的新餐巾连接一条费用的p的边,表示每天购买的新餐巾。
由每天的旧餐巾向时间加m/n处的新餐巾连接一条费用为f/s的边,表示快/慢洗的餐巾。
这样建图我们保证了,最大流一定为每天消耗的新餐巾的总和,最小费用即为最小花费。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <queue>
#define int long long
using namespace std;
#define I inline
#define R register
#define inf 2147483647
#define FOR(i,begin,end) for(R int i=begin;i<=end;++i)
#define ROF(i,begin,end) for(R int i=begin;i>=end;--i)
namespace IO{
char buf[1<<21],*pa=buf,*pb=buf;
char buffer[1<<21];int p1=-1;const int p2=(1<<21)-1;
I char gc(){return pa==pb&&(pb=(pa=buf)+fread(buf,1,1<<21,stdin),pa==pb)?EOF:*pa++;}
template<class T>I void read(T &x){
x=0;R int y=0;R char ch=gc();
for(;!isdigit(ch);ch=gc())y=ch=='-';
for(;isdigit(ch);ch=gc())x=x*10+(ch^48);
(y)&&(x=-x);return;}
I void flush(){fwrite(buffer,1,p1+1,stdout);p1=-1;return;}
I void pc(int ch){if(p1==p2)flush();buffer[++p1]=ch;return;}
template<class T>I void write(T x){
static char buf[20];static int len =-1;
if(x>=0){do buf[++len]=(x%10)^48,x/=10;while(x);}
else{pc('-');do buf[++len]=(-(x%10))^48,x/=10;while(x);}
while(len>=0)pc(buf[len--]);
return;}
}
using namespace IO;
const int maxn = 50000+500;
const int maxm = 200000+2000;
#define ci const int &
struct edge{
int u,v,f,w,n;
I edge(ci uu=0,ci vv=0,ci ff=0,ci ww=0,ci nn=0):u(uu),v(vv),f(ff),w(ww),n(nn){}
}e[maxm];
int dis[maxn],vis[maxn],cur[maxn],head[maxn],cnt=1,n,m,s,t;
int cost=0,flow=0;
I void add(ci u,ci v,ci f,ci w){
e[++cnt]=edge(u,v,f,w,head[u]),head[u]=cnt;
e[++cnt]=edge(v,u,0,-w,head[v]),head[v]=cnt;
}
I bool spfa(ci s,ci t){
memset(vis,0,sizeof vis);
memset(dis,0x3f,sizeof dis);
deque<int>q;q.push_front(t);
vis[t]=1,dis[t]=0;
while(!q.empty()){
int u=q.front();q.pop_front();
for(int ee=head[u],v;v=e[ee].v,ee;ee=e[ee].n)
if(e[ee^1].f>0&&dis[v]>dis[u]-e[ee].w){
dis[v]=dis[u]-e[ee].w;
if(!vis[v])vis[v]=1,(!q.empty()&&dis[q.front()]>dis[v])?
q.push_front(v):
q.push_back(v);
}
vis[u]=0;
}
return dis[s]==0x3f3f3f3f3f3f3f3f?0:1;
}
int dfs(ci u,ci ff){
if(u==t)return vis[t]=1,ff;
int us=0,f;vis[u]=1;
for(int ee=cur[u],v;cur[u]=ee,v=e[ee].v,ee;ee=e[ee].n)
if(vis[v]==0&&e[ee].f>0&&dis[u]-e[ee].w==dis[v]){
if((f=dfs(v,min(e[ee].f,ff-us)))>0)
cost+=f*e[ee].w,e[ee].f-=f,e[ee^1].f+=f,us+=f;
if(us==ff)break;
}
return us;
}
I void cost_flow(){
while(spfa(s,t)){
vis[t]=1;
while(vis[t]){
memcpy(cur,head,sizeof head);
memset(vis,0,sizeof vis);
flow+=dfs(s,inf);
}
}
}
int r[maxn];
#define ls(o) (o<<1)
#define rs(o) (o<<1|1)
signed main(){
read(n);
int p,t1,c1,t2,c2;
s=rs(0),t=ls(n+2);
FOR(i,1,n)
read(r[i]),add(s,ls(i),r[i],0),add(rs(i),t,r[i],0);
read(p),read(t1),read(c1),read(t2),read(c2);
FOR(i,1,n){
add(s,rs(i),inf,p);
if(i+1<=n)add(ls(i),ls(i+1),inf,0);
if(i+t1<=n)add(ls(i),rs(i+t1),inf,c1);
if(i+t2<=n)add(ls(i),rs(i+t2),inf,c2);
}
cost_flow();
write(cost);
flush();
return 0;
}
###P4013 数字梯形问题
我们考虑拆点控制流量,然后就没了。
还有无法在残量网络上继续加边跑最小费用。
洛谷好像不给数据,然后手写了一个数据生成。
我们把拆点和原点连接一条流量为1(表次数限制),费用为-点值(表示费用),然后按照题意连边即可。
将第一问拆点和原点的连边流量改为inf(表无次数限制)。
同时需要注意最下边一行的点,连接汇点T的边流量也要改为inf。
除了源点向第一行的点的连边流量为1外,其他的流量为inf(表无次数限制)
#include <bits/stdc++.h>
using namespace std;
#define I inline
#define R register
#define inf 1073742823
#define FOR(i,begin,end) for(R int i=begin;i<=end;++i)
#define ROF(i,begin,end) for(R int i=begin;i>=end;--i)
namespace IO{
char buf[1<<21],*pa=buf,*pb=buf;
char buffer[1<<21];int p1=-1;const int p2=(1<<21)-1;
I char gc(){return pa==pb&&(pb=(pa=buf)+fread(buf,1,1<<21,stdin),pa==pb)?EOF:*pa++;}
template<class T>I void read(T &x){
x=0;R int y=0;R char ch=gc();
for(;!isdigit(ch);ch=gc())y=ch=='-';
for(;isdigit(ch);ch=gc())x=(x<<3)+(x<<1)+(ch^48);
(y)&&(x=-x);return;}
I void flush(){fwrite(buffer,1,p1+1,stdout);p1=-1;return;}
I void pc(int ch){if(p1==p2)flush();buffer[++p1]=ch;return;}
template<class T>I void write(T x){
static char buf[20];static int len =-1;
if(x>=0){do buf[++len]=(x%10)^48,x/=10;while(x);}
else{pc('-');do buf[++len]=(-(x%10))^48,x/=10;while(x);}
while(len>=0)pc(buf[len--]);
return;}
}
using namespace IO;
int main(){
srand(GetTickCount());
int n=10,m=2;
write(m),pc(' '),write(n),pc('\n');
FOR(i,m,m+n-1)
{
FOR(j,1,i)write(rand()%100),pc(' ');
pc('\n');
}
flush();
return 0;
}
题目的代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <queue>
using namespace std;
#define I inline
#define R register
#define inf 1073742823
#define FOR(i,begin,end) for(R int i=begin;i<=end;++i)
#define ROF(i,begin,end) for(R int i=begin;i>=end;--i)
namespace IO{
char buf[1<<21],*pa=buf,*pb=buf;
char buffer[1<<21];int p1=-1;const int p2=(1<<21)-1;
I char gc(){return pa==pb&&(pb=(pa=buf)+fread(buf,1,1<<21,stdin),pa==pb)?EOF:*pa++;}
template<class T>I void read(T &x){
x=0;R int y=0;R char ch=gc();
for(;!isdigit(ch);ch=gc())y=ch=='-';
for(;isdigit(ch);ch=gc())x=x*10+(ch^48);
(y)&&(x=-x);return;}
I void flush(){fwrite(buffer,1,p1+1,stdout);p1=-1;return;}
I void pc(int ch){if(p1==p2)flush();buffer[++p1]=ch;return;}
template<class T>I void write(T x){
static char buf[20];static int len =-1;
if(x>=0){do buf[++len]=(x%10)^48,x/=10;while(x);}
else{pc('-');do buf[++len]=(-(x%10))^48,x/=10;while(x);}
while(len>=0)pc(buf[len--]);
return;}
}
using namespace IO;
const int maxn = 50000+500;
const int maxm = 2000000+2000;
#define ci const int &
struct edge{
int u,v,f,w,n;
I edge(ci uu=0,ci vv=0,ci ff=0,ci ww=0,ci nn=0):u(uu),v(vv),f(ff),w(ww),n(nn){}
}e[maxm];
int dis[maxn],vis[maxn],cur[maxn],head[maxn],cnt=1,n,m,s,t;
int cost=0,flow=0;
I void add(ci u,ci v,ci f,ci w){
e[++cnt]=edge(u,v,f,w,head[u]),head[u]=cnt;
e[++cnt]=edge(v,u,0,-w,head[v]),head[v]=cnt;
}
I bool spfa(ci s,ci t){
memset(vis,0,sizeof vis);
memset(dis,0x3f,sizeof dis);
deque<int>q;q.push_front(t);
vis[t]=1,dis[t]=0;
while(!q.empty()){
int u=q.front();q.pop_front();
for(int ee=head[u],v;v=e[ee].v,ee;ee=e[ee].n)
if(e[ee^1].f>0&&dis[v]>dis[u]-e[ee].w){
dis[v]=dis[u]-e[ee].w;
if(!vis[v])vis[v]=1,(!q.empty()&&dis[q.front()]>dis[v])?
q.push_front(v):
q.push_back(v);
}
vis[u]=0;
}
return dis[s]==0x3f3f3f3f?0:1;
}
int dfs(ci u,ci ff){
if(u==t)return vis[t]=1,ff;
int us=0,f;vis[u]=1;
for(int ee=cur[u],v;cur[u]=ee,v=e[ee].v,ee;ee=e[ee].n)
if(vis[v]==0&&e[ee].f>0&&dis[u]-e[ee].w==dis[v]){
if((f=dfs(v,min(e[ee].f,ff-us)))>0)
cost+=f*e[ee].w,e[ee].f-=f,e[ee^1].f+=f,us+=f;
if(us==ff)break;
}
return us;
}
I void cost_flow(){
while(spfa(s,t)){
vis[t]=1;
while(vis[t]){
memcpy(cur,head,sizeof head);
memset(vis,0,sizeof vis);
flow+=dfs(s,inf);
}
}
}
I void clear(){
memset(head,0,sizeof head);
memset(e,0,sizeof e);
cnt=1;cost=0,flow=0;
}
#define ls(o) (o<<1)
#define rs(o) (o<<1|1)
int a[50][50],id[50][50];
signed main(){
s=ls(0),t=rs(0);
int tot=0;
read(m),read(n);
FOR(i,m,m+n-1)
FOR(j,1,i)
read(a[i][j]),id[i][j]=++tot;
// work 1
FOR(i,1,m)
add(s,ls(id[m][i]),1,0);
FOR(i,m,m+n-1)
FOR(j,1,i)
add(ls(id[i][j]),rs(id[i][j]),1,-a[i][j]);
FOR(i,m,m+n-2)
FOR(j,1,i)
add(rs(id[i][j]),ls(id[i+1][j]),1,0),
add(rs(id[i][j]),ls(id[i+1][j+1]),1,0);
FOR(i,1,m+n-1)
add(rs(id[m+n-1][i]),t,1,0);
cost_flow();
write(-cost),pc('\n');
// work 2
clear();
FOR(i,1,m)
add(s,ls(id[m][i]),1,0);
FOR(i,m,m+n-1)
FOR(j,1,i)
add(ls(id[i][j]),rs(id[i][j]),inf,-a[i][j]);
FOR(i,m,m+n-2)
FOR(j,1,i)
add(rs(id[i][j]),ls(id[i+1][j]),1,0),
add(rs(id[i][j]),ls(id[i+1][j+1]),1,0);
FOR(i,1,m+n-1)
add(rs(id[m+n-1][i]),t,1,0);
cost_flow();
write(-cost),pc('\n');
// work 3
clear();
FOR(i,1,m)
add(s,ls(id[m][i]),1,0);
FOR(i,m,m+n-1)
FOR(j,1,i)
add(ls(id[i][j]),rs(id[i][j]),inf,-a[i][j]);
FOR(i,m,m+n-2)
FOR(j,1,i)
add(rs(id[i][j]),ls(id[i+1][j]),inf,0),
add(rs(id[i][j]),ls(id[i+1][j+1]),inf,0);
FOR(i,1,m+n-1)
add(rs(id[m+n-1][i]),t,inf,0);
cost_flow();
write(-cost),pc('\n');
flush();
return 0;
}
大概本博客就完结了,网络流二十四题的题目连接直接放到下面了:
P1251 餐巾计划问题
P2754 [CTSC1999]家园 / 星际转移问题
P2756 飞行员配对方案问题
P2761 软件补丁问题
P2762 太空飞行计划问题
P2763 试题库问题
P2764 最小路径覆盖问题
P2765 魔术球问题
P2766 最长不下降子序列问题
P2770 航空路线问题
P2774 方格取数问题
P2775 机器人路径规划问题
P3254 圆桌问题
P3355 骑士共存问题
P3356 火星探险问题
[P3357 最长k可重线段集问题]https://www.luogu.com.cn/problem/P3357)
P3358 最长k可重区间集问题
P4009 汽车加油行驶问题
P4011 孤岛营救问题
P4012 深海机器人问题
P4013 数字梯形问题
P4014 分配问题
P4015 运输问题
P4016 负载平衡问题
##当然网络流24题只是比较基础的入门题目,本博客只提供入门方面的参考
]]>咕咕咕
]]>咕咕咕
]]>