20190718

it2022-05-05  169

T1缩点:

将强连通分量缩为一点

#include<bits/stdc++.h> using namespace std; struct edge{     int u,v; }; edge e[100005],newe[100005]; bool v[10005],vis[10005]; int dfn[10005],n,m,f[10005],ne[100005],k[10005],now,low[10005],s[10005],top,zz[10005],newf[10005],newne[100005],newn,newm,newk[10005],scc[10005],dp[10005]; //scc:相同时间点的位置  inline int read(){     int k=0,f=1;     char c=getchar();     for(;!isdigit(c);c=getchar())       if(c=='-')         f=-1;     for(;isdigit(c);c=getchar())       k=k*10+c-'0';     return k*f; } inline void tarjan(int x){     dfn[x]=low[x]=++now;     s[++top]=x;     v[x]=true;     for(int i=f[x];i;i=ne[i]){         int y=e[i].v;         if(!dfn[y]){             tarjan(y);             low[x]=min(low[x],low[y]);         }         else if(dfn[y]&&v[y])           low[x]=min(low[x],dfn[y]);     }     if(low[x]==dfn[x]){         while(s[top]!=x)           v[s[top]]=false,s[top]=0,top--;         v[x]=false;         s[top]=0;         top--;     }     return ;  } int main(){     n=read(),m=read();     for(int i=1;i<=n;i++)       k[i]=read();     for(int i=1;i<=m;i++){         e[i].u=read(),e[i].v=read();         ne[i]=f[e[i].u];         f[e[i].u]=i;     }     for(int i=1;i<=n;i++)       if(!dfn[i])         zz[i]=true,tarjan(i); //    for(int i=1;i<=n;i++) //      cout<<dfn[i]<<" "<<low[i]<<endl;     for(int i=1;i<=n;i++){         if(!scc[low[i]]){             newn++;             scc[low[i]]=newn;         }         newk[scc[low[i]]]+=k[i];     }      for(int i=1;i<=n;i++){         for(int j=f[i];j;j=ne[j]){             int c=e[j].v;             if(scc[low[c]]!=scc[low[i]]){                 newm++;                 newe[newm].u=scc[low[i]];                 newe[newm].v=scc[low[c]];                 newne[newm]=newf[scc[low[i]]];                 newf[scc[low[i]]]=newm;             }         }     }     for(int i=1;i<=newn;i++){         cout<<i<<":"<<newk[i]<<endl;         for(int j=newf[i];j;j=newne[j])           cout<<newe[j].v<<" ";         cout<<endl;     } }

T2二分图最大匹配:

题目背景

二分图

感谢@一扶苏一 提供的hack数据

题目描述

给定一个二分图,结点个数分别为n,m,边数为e,求二分图最大匹配数

输入输出格式

输入格式:

 

第一行,n,m,e

第二至e+1行,每行两个正整数u,v,表示u,v有一条连边

 

输出格式:

 

共一行,二分图最大匹配

 

输入输出样例

输入样例#1: 复制

1 1 1 1 1

输出样例#1: 复制

1

说明

n,m \leq 1000n,m≤1000, 1 \leq u \leq n1≤u≤n, 1 \leq v \leq m1≤v≤m ,e \le n\times me≤n×m

因为数据有坑,可能会遇到 v>mv>m 或者 u>nu>n 的情况。请把 v>mv>m 或者 u>nu>n 的数据自觉过滤掉。

算法:二分图匹配

#include<bits/stdc++.h> using namespace std; int bs,n,m,s,t,f[10005],ne[800005],d[10005],maxflow,x,y; queue<int>q; struct edge{     int u,v,c,f; }e[800005]; inline int read(){     int k=0,f=1;     char c=getchar();     for(;!isdigit(c);c=getchar())       if(c=='-')         f=-1;     for(;isdigit(c);c=getchar())       k=k*10+c-'0';     return k*f; } inline bool bfs(){     memset(d,0,sizeof(d));     while(q.size())  q.pop();     q.push(s);     d[s]=1;     while(q.size()){         int x=q.front();q.pop();         for(int i=f[x];i;i=ne[i])           if(e[i].f&&!d[e[i].v]){               q.push(e[i].v);               d[e[i].v]=d[x]+1;               if(e[i].v==t)                 return true;           }     }      return false; } inline int dinic(int x,int flow){     if(x==t)       return flow;     int rest=flow,k;     for(int i=f[x];i&&rest;i=ne[i]){         if(e[i].f&&d[e[i].v]==d[x]+1){             k=dinic(e[i].v,min(rest,e[i].f));             if(!k)               d[e[i].v]=0;             e[i].f-=k;             e[i+1].f+=k;             rest-=k;         }     }     return flow-rest; } int main(){     n=read(),m=read(),bs=read();     s=n+m+1,t=n+m+2;     for(int i=1;i<=bs*2;i+=2){         x=read(),y=read();         if(x>n||y>m)           continue;         e[i+1].v=e[i].u=x,e[i+1].u=e[i].v=y+n;e[i].f=1;         ne[i]=f[e[i].u],f[e[i].u]=i;         e[i+1].f=0;         ne[i+1]=f[e[i+1].u],f[e[i+1].u]=i+1;     }     for(int i=bs*2+1;i<=(bs+n)*2;i+=2){         e[i].u=s,e[i].v=(i-bs*2)/2+1;         e[i].f=1;         e[i+1].u=(i-bs*2)/2+1;         e[i+1].v=s;         e[i+1].f=0;         ne[i]=f[e[i].u],f[e[i].u]=i;         ne[i+1]=f[e[i+1].u],f[e[i+1].u]=i+1;     }     for(int i=(bs+n)*2+1;i<=(bs+m+n)*2;i+=2){         e[i+1].u=t,e[i+1].v=(i-(bs+n)*2)/2+1+n;         e[i].f=1;         e[i].u=(i-(bs+n)*2)/2+1+n;         e[i].v=t;         e[i+1].f=0;         ne[i]=f[e[i].u],f[e[i].u]=i;         ne[i+1]=f[e[i+1].u],f[e[i+1].u]=i+1;     }     int flow=0;     while(bfs())       while(flow=dinic(s,1e9))         maxflow+=flow;     cout<<maxflow;     return 0; }

T3网络最大流:

题目描述

如题,给出一个网络图,以及其源点和汇点,求出其网络最大流。

输入输出格式

输入格式:

 

第一行包含四个正整数N、M、S、T,分别表示点的个数、有向边的个数、源点序号、汇点序号。

接下来M行每行包含三个正整数ui、vi、wi,表示第i条有向边从ui出发,到达vi,边权为wi(即该边最大流量为wi)

 

输出格式:

 

一行,包含一个正整数,即为该网络的最大流。

 

输入输出样例

输入样例#1: 复制

4 5 4 3 4 2 30 4 3 20 2 3 20 2 1 30 1 3 40

输出样例#1: 复制

50

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=10,M<=25

对于70%的数据:N<=200,M<=1000

对于100%的数据:N<=10000,M<=100000

样例说明:

题目中存在3条路径:

4-->2-->3,该路线可通过20的流量

4-->3,可通过20的流量

4-->2-->1-->3,可通过10的流量(边4-->2之前已经耗费了20的流量)

故流量总计20+20+10=50。输出50

#include<bits/stdc++.h> using namespace std; int n,m,s,t,f[10005],ne[200005],d[10005],maxflow; queue<int>q; struct edge{     int u,v,c,f; }e[200005]; inline int read(){     int k=0,f=1;     char c=getchar();     for(;!isdigit(c);c=getchar())       if(c=='-')         f=-1;     for(;isdigit(c);c=getchar())       k=k*10+c-'0';     return k*f; } inline bool bfs(){     memset(d,0,sizeof(d));     while(q.size())  q.pop();     q.push(s);     d[s]=1;     while(q.size()){         int x=q.front();q.pop();         for(int i=f[x];i;i=ne[i])           if(e[i].f&&!d[e[i].v]){               q.push(e[i].v);               d[e[i].v]=d[x]+1;               if(e[i].v==t)                 return true;           }     }      return false; } inline int dinic(int x,int flow){     if(x==t)       return flow;     int rest=flow,k;     for(int i=f[x];i&&rest;i=ne[i]){         if(e[i].f&&d[e[i].v]==d[x]+1){             k=dinic(e[i].v,min(rest,e[i].f));             if(!k)               d[e[i].v]=0;             e[i].f-=k;             e[i+1].f+=k;             rest-=k;         }     }     return flow-rest; } int main(){     n=read(),m=read(),s=read(),t=read();     for(int i=1;i<=m*2;i+=2){         e[i+1].v=e[i].u=read(),e[i+1].u=e[i].v=read();e[i].f=read();         ne[i]=f[e[i].u],f[e[i].u]=i;         e[i+1].f=0;         ne[i+1]=f[e[i+1].u],f[e[i+1].u]=i+1;     }     int flow=0;     while(bfs())       while(flow=dinic(s,1e9))         maxflow+=flow;     cout<<maxflow;     return 0; }

T4割点:

题目背景

割点

题目描述

给出一个nn个点,mm条边的无向图,求图的割点。

输入输出格式

输入格式:

 

第一行输入n,mn,m

下面mm行每行输入x,yx,y表示xx到yy有一条边

 

输出格式:

 

第一行输出割点个数

第二行按照节点编号从小到大输出节点,用空格隔开

 

输入输出样例

输入样例#1: 复制

6 7 1 2 1 3 1 4 2 5 3 5 4 5 5 6

输出样例#1: 复制

1 5

说明

对于全部数据,n \le 20000n≤20000,m \le 100000m≤100000

点的编号均大于00小于等于nn。

tarjan图不一定联通。

#include<bits/stdc++.h> using namespace std; struct edge{     int u,v; }e[2000005]; bool v[200005],pd,zz[200005],ans[200005]; int n,m,f[200005],ne[2000005],dfn[200005],low[200005],now,front[200005],tot,answ; inline int read(){     int k=0,f=1;     char c=getchar();     for(;!isdigit(c);c=getchar())       if(c=='-')         f=-1;     for(;isdigit(c);c=getchar())       k=k*10+c-'0';     return k*f; } inline void dfs(int x){     low[x]=dfn[x]=++now;     int has=0;     for(int i=f[x];i;i=ne[i]){         int y=e[i].v;         if(!dfn[y]){             dfs(e[i].v);             low[x]=min(low[x],low[y]);             if(low[y]>=dfn[x]){                 has++;                 if(has>1||!zz[x]){                     if(!ans[x])                       answ++;                     ans[x]=true;                 }             }         }         else           low[x]=min(low[x],dfn[y]);     }     return ; } int main(){     n=read();     m=read();     for(int i=1;i<=2*m;i+=2){         e[i+1].v=e[i].u=read(),e[i+1].u=e[i].v=read();         ne[i]=f[e[i].u],f[e[i].u]=i;         ne[i+1]=f[e[i+1].u],f[e[i+1].u]=i+1;     }     for(int i=1;i<=n;i++){         if(!dfn[i])           zz[i]=true,dfs(i);     } //    cout<<ans.size()<<endl; //    while(ans.size()){ //        cout<<-ans.top()<<" "; //        ans.pop(); //    }     cout<<answ<<endl;     for(int i=1;i<=n;i++)       if(ans[i])         cout<<i<<" ";     return 0; }


最新回复(0)