码迷,mamicode.com
首页 > 其他好文 > 详细

网络流24题!!!!

时间:2019-05-20 00:59:46      阅读:93      评论:0      收藏:0      [点我收藏+]

标签:tps   sizeof   ems   问题   取消   break   试题   答案   har   

网1:飞行员匹配

题目链接:https://www.oj.swust.edu.cn/problem/show/1736

俩种做法:

技术图片
/**********二分图匹配做法***********/
#include<bits/stdc++.h>
using namespace std;
const int M=102;
int n,m;
int e[M][M],match[M],used[M];
bool find(int u){
    for(int i=1;i<=m;i++){
        if(e[u][i]==1&&used[i]==0){
            used[i]=1;
            if(match[i]==0||find(match[i])){
                match[i]=u;
                return true;
            }
        }
    }
    return false;
}
int main(){
    scanf("%d%d",&m,&n);
    int x,y;
    while(~scanf("%d%d",&x,&y)){
        if(x==-1&&y==-1)
            break;
         
        e[x][y]=1;
        e[y][x]=1;
    }
//  if(m==n||m==0)
         
    int ans=0;
    for(int i=m+1;i<=n;i++){
        memset(used,0,sizeof(used));
        if(find(i))
            ans++;
    }
    if(ans==0)
        return puts("No Solution!"),0;
    printf("%d\n",ans);
    for(int i=1;i<=m;i++)
        if(match[i])
            printf("%d %d\n",i,match[i]);
    return 0;
}
/***************网络流**************/
#include<bits/stdc++.h>
using namespace std;
const int M=505;
int cur[M],deep[M],head[M],s,t,tot;
const int inf=0x3f3f3f3f;
struct node{
    int v,nextt,w;
}e[M*50];
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=0;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
bool bfs(){
    memset(deep,0,sizeof(deep));
    queue<int>que;
    que.push(s);
    deep[s]=1;
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];i!=-1;i=e[i].nextt){
            int v=e[i].v;
            if(e[i].w>0&&deep[v]==0){
                deep[v]=deep[u]+1;
                if(v==t)
                    return true;
                que.push(v);
            }
        }
    }
    return deep[t]==0?false:true;
}
int dfs(int u,int fl){
    if(u==t)
        return fl;
    int x=0,ans=0;
    for(int i=cur[u];i!=-1;i=e[i].nextt){
        int v=e[i].v;
        if(deep[u]+1==deep[v]&&e[i].w>0){
            x=dfs(v,min(fl-ans,e[i].w));
            e[i].w-=x;
            e[i^1].w+=x;
            if(e[i].w)
                cur[u]=i;
            ans+=x;
            if(ans==fl)
                return fl;
        }
    }
    if(ans==0)
        deep[u]=0;
    return ans;
}
int dinic(int n){
    int ans=0;
    while(bfs()){
        for(int i=0;i<=t;i++)
            cur[i]=head[i];
        ans+=dfs(s,inf);
    }
    return ans;
}
int main(){
    memset(head,-1,sizeof(head));
    int n,m;
    cin>>m>>n;
    s=0,t=n+1;
    for(int i=1;i<=m;i++){
        addedge(s,i,1);
    }
    for(int i=m+1;i<=n;i++){
        addedge(i,t,1);
    }
    int x,y;
    while(~scanf("%d%d",&x,&y)){
        if(x==-1&&y==-1)
            break;
        addedge(x,y,1);
    }
    int ans=dinic(t);
    if(ans==0)
        return puts("No Solution!"),0;
    printf("%d\n",ans);
    for(int i=m+1;i<=n;i++)
        for(int j=head[i];j!=-1;j=e[j].nextt)
            if(e[j].v!=t&&e[j].w==1)
                printf("%d %d\n",e[j].v,i);
    return 0;
}
View Code

网2:飞行员计划问题

题目链接:https://www.oj.swust.edu.cn/problem/show/1737

最大权闭合图(总的答案就是最小路径覆盖的答案)

从起点往每个权值为正的点建立一条边,容量为点权值。

每个权值为负的点往终点建立一条边,容量为权值的绝对值。

如果选A就必须选B 则就从A建立一条往B的边,容量为inf。

 

最大权闭合图的点就是从起点开始广搜,权值为0的点不走,能走到的点就是被选中的点。

dinic最后一次bfs的d数组正好可以用来判断这个条件。

技术图片
#include<bits/stdc++.h>
using namespace std;
const int M=505;
const int inf=0x3f3f3f3f;
struct node{
    int v,w,nextt;
}e[M*50];
int head[M],cur[M],deep[M],s,t,tot;
bool bfs(){
    memset(deep,0,sizeof(deep));
    queue<int >que;
    que.push(s);
    deep[s]=1;
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];i!=-1;i=e[i].nextt){
            int v=e[i].v;
            if(e[i].w>0&&deep[v]==0){
                deep[v]=deep[u]+1;
                if(v==t)
                    return true;;
                que.push(v);
            }    
        }
    }
    return false;
}
int dfs(int u,int fl){
    if(u==t)
        return fl;
    int ans=0,x=0;
    for(int i=cur[u];i!=-1;i=e[i].nextt){
        int v=e[i].v;
        if(e[i].w>0&&deep[v]==deep[u]+1){
            x=dfs(v,min(e[i].w,fl-ans));
            e[i].w-=x;
            e[i^1].w+=x;
            if(e[i].w)
                cur[u]=i;
            
            ans+=x;
            if(ans==fl)
                return fl;
        }
    }
    if(ans==0)
        deep[u]=0;
    return ans;
}
int dinic(int n){
    int ans=0;
    while(bfs()){
        for(int i=0;i<=n;i++)
            cur[i]=head[i];
        ans+=dfs(s,inf);
    }
    return ans;
}
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=0;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
void init(){
    memset(head,-1,sizeof(head));
    tot=0;
}
int main(){
    
    init();
    int m,n;
    cin>>m>>n;
    s=0,t=n+m+1;
    int sum=0;
    for(int i=1;i<=m;i++){
        int w;
        scanf("%d",&w);
        addedge(s,n+i,w);
        sum+=w;
        int x;
        char ch;
        while(true){
            scanf("%d%c",&x,&ch);
            addedge(n+i,x,inf);
            if(ch==\r||ch==\n)
                break;
        }
    }
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        addedge(i,t,x);
    }
    sum-=dinic(t);
    
    for(int i=1;i<=m;i++){
        if(deep[n+i])
            printf("%d ",i);
    }
    putchar(\n);
    for(int i=1;i<=n;i++){
        if(deep[i])
            printf("%d ",i);
    }
    putchar(\n);
    
    
    
    
    
    printf("%d\n",sum);
    return 0;
}
View Code

3、最小路径覆盖问题

题目链接:https://loj.ac/problem/6002

最小路径覆盖问题模型,拆点做最大匹配,总点数减去最大流为需要的最少的边数

题目有建图方法

拆点意思是这样的,第i个点的流量流向第j个点时表示第i个点的下一个点是j点,剩下的没办法流向终点的点就是没有点能到它那里,说明这个点是边的起点,根据这个来递归可以用来查找答案方案。

技术图片
#include<bits/stdc++.h>
using namespace std;
const int M=505; 
const int inf=0x3f3f3f3f;
struct node{
    int v,nextt,w;
}e[M*50];
int head[M],book[M],cur[M],deep[M],s,t,tot,n;
inline int read(){
    int sum=0,x=1;
    char ch=getchar();
    while(ch<0||ch>9){
        if(ch==-)
            x=0;
        ch=getchar();
    }
    while(ch>=0&&ch<=9)
        sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
    return x?sum:-sum;
}
inline void write(int x){
    if(x<0)
        putchar(-),x=-x;
    if(x>9)
        write(x/10);
    putchar(x%10+0);
}
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=0;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
bool bfs(){
    memset(deep,0,sizeof(deep));
    queue<int>que;
    que.push(s);
    deep[s]=1;
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];i!=-1;i=e[i].nextt){
            int v=e[i].v;
            if(e[i].w>0&&deep[v]==0){
                deep[v]=deep[u]+1;
                if(v==t)
                    return true;
                que.push(v);
            }
        }
    }
    return deep[t]==0?false:true;
}
int dfs(int u,int fl){
    if(u==t)
        return fl;
    int ans=0,x=0;
    for(int i=cur[u];i!=-1;i=e[i].nextt){
        int v=e[i].v;
        if(e[i].w>0&&deep[v]==deep[u]+1){
            x=dfs(v,min(e[i].w,fl-ans));
            e[i].w-=x;
            e[i^1].w+=x;
            if(e[i].w)
                cur[u]=i;
            ans+=x;
            if(ans==fl)
                return ans;
        }
    }
    if(ans==0)
        deep[u]=0;
    return ans;
}
int dinic(int n){
    int ans=0;
    while(bfs()){
        for(int i=0;i<=n;i++)
            cur[i]=head[i];
        ans+=dfs(s,inf);
    }
    return ans;
}
void dfs2(int u,int &flag){
    int point=u+n;
    book[u]=1;
    for(int i=head[point];i!=-1;i=e[i].nextt){
        if(e[i].v!=t&&e[i].w==1){
            dfs2(e[i].v,flag);
        }
    }
    
    if(flag==1)
        flag=0;
    else
        putchar( );
    write(u);
}
void init(){
    tot=0;
    memset(head,-1,sizeof(head));
}
int main(){
    init();
    n=read();
    int m;
    m=read();
    s=0,t=(n<<1)+1;
    for(int i=1;i<=n;i++)
        addedge(s,i,1),addedge(i+n,t,1);
    while(m--){
        int x=read(),y=read();
        addedge(x,y+n,1);
    }
    int sum=n-dinic(t);
    for(int i=head[t];i!=-1;i=e[i].nextt){
        int flag=1;
        if(!book[e[i].v-n]&&e[i].w==1){
            dfs2(e[i].v-n,flag);
            puts("");
        }
    }
    for(int i=1;i<=n;i++)
        if(!book[i])
            write(i),putchar(\n);
    write(sum);
    putchar(\n);
    return 0;
}
View Code

4、魔术球问题

题目链接:https://www.oj.swust.edu.cn/problem/show/1739

网络流跑形成的每条链就是题目要求的管子
由此答案就是各个点形成网络流的最小路径覆盖

因为网络流是在残量网络流上跑的,所以我们每次加一个点进去,在把符合条件的边加上去

注意判断条件:for(i=1; i-ans<=n+1; i++)
当加到刚好超过给点的n时即为答案,I是网络流上的点(除起点,汇点外),ans是最大流;

然后输出方案那里/2的意思因为我每次建点都是健俩点,所以输出方案点数编号的时候对应的就是其1/2倍。

技术图片
#include<bits/stdc++.h>
using namespace std;
const int M=11111;
const int inf=0x3f3f3f3f;
struct node
{
    int v,nextt,w;
}e[M*20];
int head[M],cur[M],deep[M],hei[M],y[M],book[M],s,t,tot,cnt;

inline int read(){
    int sum=0,sign=1;
    char ch=getchar();
    while(ch<0||ch>9){
        if(ch==-)
            sign=0;
        ch=getchar();
    }
    while(ch>=0&&ch<=9)
        sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
    return sign?sum:-sum;
}
inline void write(int f){
    if(f<0)
        putchar(-),f=-f;
    if(f>9)
        write(f/10);
    putchar(f%10+0);
}
bool bfs(){
    memset(deep,0,sizeof(deep));
    queue<int>que;
    que.push(s);
    deep[s]=1;
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(e[i].w>0&&deep[v]==0){
                deep[v]=deep[u]+1;
                if(v==t)
                    return true;
                que.push(v);
            }
        }
    }
    return deep[t]==0?false:true;
}
int dfs(int u,int fl){
    if(u==t)
        return fl;
    int ans=0,p=0;
    for(int i=cur[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(deep[v]==deep[u]+1&&e[i].w>0){
            p=dfs(v,min(fl-ans,e[i].w));
            e[i].w-=p;
            e[i^1].w+=p;
            if(e[i].w)
                cur[u]=i;
            ans+=p;
            if(ans==fl)
                return fl;
        }
    }
    if(ans==0)
        deep[u]=0;
    return ans;
}
int dinic(int n){
    int ans=0;
    while(bfs())
    {
        for(int i=0;i<=n;i++)
            cur[i]=head[i];
        ans+=dfs(s,inf);
    }
    return ans;
}
void init(){
    memset(head,-1,sizeof(head));
    tot=0,cnt=2;
}
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=0;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
void prin(int u2,int &flag){
    book[u2]=1;
    int u=y[u2];
    for(int i=head[u];~i;i=e[i].nextt){
        if(e[i].w==1&&e[i].v!=t)
            prin(e[i].v/2,flag);
    }
    if(flag)
        flag=0;
    else
        putchar( );
    write(u2);
}
int main(){
    init();
    int n=read();
    s=0,t=11110;
    int i,ans=0;
    for(i=1;i-ans<=n+1;i++){
        hei[i]=cnt++;
        y[i]=cnt++;
        addedge(s,hei[i],1);
        addedge(y[i],t,1);
        for(int j=1;j<i;j++){
            int l=sqrt(i+j);
            if(l*l==i+j){
                addedge(hei[j],y[i],1);
            }
        }
        ans+=dinic(t);
    }
    int sum=i-2;
    write(sum);
    putchar(\n);
    int flag=1;
    for(int i=head[t];~i;i=e[i].nextt){
        if(e[i].w==1&&!book[e[i].v/2]){
            flag=1;
            prin(e[i].v/2,flag);
            putchar(\n);
        }
    }
    for(int i=1;i<=sum;i++)
        if(!book[i])
            write(i),putchar(\n);
    return 0;
    
}
View Code

5、圆桌问题

题目链接:https://www.luogu.org/problemnew/show/P3254

建图问题:健超级源点s,超级汇点t
s向每个代表连一条边,容量为人数------1
每个代表向每个圆桌拆个点出来连,容量为1(代表要一个人)-----2
最后每个圆桌向超级汇点连边,容量为圆桌允许人数ci-----3
第一步的编号为:1~n;
第二步的编号为:n+1~n+n*m;
第三步的编号为:n+n*m+1~n+n*m+m;
所以t编号为n+n*m+m+1;
跑网络流看最大流等不等与代表总人数


然后就是输出方案:
因为有走过,所以邻接边为1(看代码应该看得懂)
输出答案的话就找那个限制流量的边,如果那个边走过了就说明这个点有用嘛,找一下输出就行。

技术图片
#include<bits/stdc++.h>
using namespace std;
const int M=50005;
const int inf=0x3f3f3f3f;
struct node{
    int v,nextt,w;
}e[M*20];
int head[M],cur[M],deep[M],tot,s,t;
inline int read(){
    int sum=0,x=1;
    char ch=getchar();
    while(ch<0||ch>9){
        if(ch==-)
            x=0;
        ch=getchar();
    }
    while(ch>=0&&ch<=9)
        sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
    return x?sum:-sum;
}
inline void write(int x){
    if(x<0)
        putchar(-),x=-x;
    if(x>9)
        write(x/10);
    putchar(x%10+0);
}
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=0;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
bool bfs(){
    memset(deep,0,sizeof(deep));
    deep[s]=1;
    queue<int>que;
    que.push(s);
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(deep[v]==0&&e[i].w>0){
                deep[v]=deep[u]+1;
                if(v==t)
                    return true;
                que.push(v);
            }
        }
    }
    return deep[t]==0?false:true;
}
int dfs(int u,int fl){
    if(u==t)
        return fl;
    int ans=0,x=0;
    for(int i=cur[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(e[i].w>0&&deep[v]==deep[u]+1){
            x=dfs(v,min(fl-ans,e[i].w));
            e[i].w-=x;
            e[i^1].w+=x;
            if(e[i].w)
                cur[u]=i;
            ans+=x;
            if(ans==fl)
                return ans;
        }
    }
    if(ans==0)
        deep[u]=0;
    return ans;
}
int dinic(int n){
    int ans=0;
    while(bfs()){
        for(int i=0;i<=n;i++)
            cur[i]=head[i];
        ans+=dfs(s,inf);
    }
    return ans;
}
void init(){
    tot=0;
    memset(head,-1,sizeof(head));
}
vector<int>a[M];
int main(){
    init();
    int n=read(),m=read();
    s=0,t=n+n*m+m+1;
    int sum=0;
    for(int i=1;i<=n;i++){
        int x=read();
        sum+=x;
        addedge(s,i,x);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            addedge(i,n+(i-1)*m+j,1);
            addedge(n+(i-1)*m+j,n+n*m+j,1);
        }
    }
    for(int i=1;i<=m;i++){
        int x=read();
        addedge(n+n*m+i,t,x);
    }
    if(dinic(t)==sum){
        puts("1");
    }
    else
        return puts("0"),0;
    //cout<<"!!"<<endl;
    for(int i=1;i<=m;i++){
        for(int j=head[n+n*m+i];~j;j=e[j].nextt){
            if(e[j].v!=t&&e[j].w==1){
                a[(e[j].v-n-i)/m+1].push_back(i);
            }
        }
    }
    for(int i=1;i<=n;i++){
        write(a[i][0]);
        for(int j=1;j<a[i].size();j++)
            putchar( ),write(a[i][j]);
        putchar(\n);
    }
    return 0;
}
View Code

6、最长递增子序列问题

题目链接:https://www.luogu.org/problemnew/show/P2766

第一问就用nlogn的dp去做,然后第二问第三问就用dp过程来模拟走网络流过程,建图也是如此;


将每个点拆点边权为1(代表只能用一次),然后其他看代码建图应该能懂;

 

第三问特殊地要求x1和xn可以重复使用,只需取消这两个点相关边的流量限制,求网络最大流即可。

技术图片
#include<bits/stdc++.h>
using namespace std;
const int M=805;
const int  inf=0x3f3f3f3f;
struct node{
    int v,nextt,w;
}e[20005];
int head[20005],cur[20005],deep[20005],s,t,tot,a[M],dp[M];
void init(){
    tot=0;
    memset(head,-1,sizeof(head));
}
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=0;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
bool bfs(){
    memset(deep,0,sizeof(deep));
    queue<int>que;
    que.push(s);
    deep[s]=1;
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(deep[v]==0&&e[i].w>0){
                deep[v]=deep[u]+1;
                if(v==t)
                    return true;
                que.push(v);
            }
        }
    }
    return deep[t]==0?false:true;
}
int dfs(int u,int fl){
    if(u==t)
        return fl;
    int x=0,ans=0;
    for(int i=cur[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(deep[v]==deep[u]+1&&e[i].w>0){
            x=dfs(v,min(fl-ans,e[i].w));
            e[i].w-=x;
            e[i^1].w+=x;
            if(e[i].w)
                cur[u]=i;
            ans+=x;
            if(ans==fl)
                return ans;
        }
    }
    if(ans==0)
        deep[u]=0;
    return ans;
}
int dinic(int n){
    int ans=0;
    while(bfs()){
        for(int i=0;i<=n;i++)
            cur[i]=head[i];
        ans+=dfs(s,inf);
    }
    return ans;
}
int main(){
    int n;
    scanf("%d",&n);
    s=0,t=n*2+1;
    init();
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        dp[i]=1;
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
            if(a[i]>=a[j])
                dp[i]=max(dp[j]+1,dp[i]);
    int ans=0;
    for(int i=1;i<=n;i++){
        ans=max(ans,dp[i]);
    }
    for(int i=1;i<=n;i++)
        if(dp[i]==ans)
            addedge(s,i,1);
            
    for(int i=1;i<=n;i++)
        addedge(i+n,i,1);
        
    for(int i=1;i<=n;i++)
        if(dp[i]==1)
            addedge(i,t,1);
            
    for(int i=1;i<=n;i++)
        for(int j=1;j<i;j++)
            if(a[i]>=a[j]&&dp[i]==dp[j]+1)
                addedge(i,j+n,1);
    int c=dinic(t);
    printf("%d\n%d\n",ans,c);    
    if(dp[n]==ans)
        addedge(s,n,inf);
    addedge(1+n,1,inf);
    addedge(1,t,inf);
    c+=dinic(t);
    printf("%d\n",c);
    return 0;    
}
View Code

7、试题库问题

题目链接:https://www.luogu.org/problemnew/show/P2763

////把k个项目向汇点t连容量为ki的容量;
把n个点拆点出来,容量为1(代表用一次)

技术图片
#include<bits/stdc++.h>
using namespace std;
const int M=5e+5;
const int inf=0x3f3f3f3f;
struct node{
    int v,w,nextt;
}e[M<<1];
int head[M],cur[M],deep[M],s,t,tot;
bool bfs(){
    memset(deep,0,sizeof(deep));
    queue<int>que;
    deep[s]=1;
    que.push(s);
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(deep[v]==0&&e[i].w>0){
                deep[v]=deep[u]+1;
                if(v==t)
                    return true;
                que.push(v);
            }
        }
    }
    return deep[t]==0?false:true;
}
int dfs(int u,int fl){
    if(u==t)
        return fl;
    int ans=0,x=0;
    for(int i=head[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(deep[v]==deep[u]+1&&e[i].w>0){
            x=dfs(v,min(fl-ans,e[i].w));
            e[i].w-=x;
            e[i^1].w+=x;
            if(e[i].w)
                cur[u]=i;
            ans+=x;
            if(ans==fl)
                return ans;
        }
    }
    if(ans==0)
        deep[u]=0;
    return ans;
}
int dinic(int n){
    int ans=0;
    while(bfs()){
        for(int i=0;i<=n;i++)
            cur[i]=head[i];
        ans+=dfs(s,inf);

    }
    return ans;
}
void init(){
    memset(head,-1,sizeof(head));
    tot=0;
    
}
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=0;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
int main(){
    init();
    int k,n;
    scanf("%d%d",&k,&n);
    s=0,t=2*n+k+1;
    int sum=0;
    for(int i=1;i<=k;i++){
        int x;
        scanf("%d",&x);
        addedge(i,t,x);
        sum+=x;
    }
    for(int i=1;i<=n;i++)
        addedge(s,k+i,1);
    for(int i=1;i<=n;i++){
        int p;
        addedge(k+i,k+i+n,1);
        scanf("%d",&p);
        while(p--){
            int sign;
            scanf("%d",&sign);
            addedge(k+i+n,sign,1);
        }
    }
    if(dinic(t)!=sum)
        return puts("No Solution!"),0;
    for(int i=1;i<=k;i++){
        printf("%d:",i);
        for(int j=head[i];~j;j=e[j].nextt){
            if(e[j].v!=t&&e[j].w==1){
                printf(" %d",e[j].v-k-n);
            }
        }
        putchar(\n);
    }
    return 0;
}
View Code

8、机器人路径规划问题

不会题;

9、方格取数问题

题目链接:https://www.luogu.org/problemnew/show/P2774

方格取数
题目说不能取有边界

那么我们建图的时候就按有边界的取建图;
我们可以这样理解,我们要去掉一些格子,让整个图按要求联通,达到最大;
把每个方格拆点,边权为方格的值,最大对应全部-最小,最小什么呢?即最小割;

技术图片
#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int sum=0,x=1;
    char ch=getchar();
    while(ch<0||ch>9){
        if(ch==-)
            x=0;
        ch=getchar();
    }
    while(ch>=0&&ch<=9){
        sum=(sum<<1)+(sum<<3)+(ch^48),ch=getchar();
    }
    return x?sum:-sum;
}
inline void write(int x){
    if(x<0)
        putchar(-),x=-x;
    if(x>9)
        write(x/10);
    putchar(x%10+0);
}
const int M=2e4+4;
const int inf=0x3f3f3f3f;
struct node{
    int v,nextt,w;
}e[200005];
int head[M],deep[M],cur[M];
int tot,s,t;
int gx[4]={1,-1,0,0};
int gy[4]={0,0,-1,1};
int a[102][102];
void init(){
    memset(head,-1,sizeof(head));
    tot=0;
}
void addedge(int u,int v,int w){
    e[tot].v=v;
    e[tot].w=w;
    e[tot].nextt=head[u];
    head[u]=tot++;
    e[tot].v=u;
    e[tot].w=0;
    e[tot].nextt=head[v];
    head[v]=tot++;
}
bool bfs(){
    memset(deep,0,sizeof(deep));
    deep[s]=1;
    queue<int>que;
    que.push(s);
    while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int i=head[u];~i;i=e[i].nextt){
            int v=e[i].v;
            if(e[i].w>0&&deep[v]==0){
                deep[v]=deep[u]+1;
                if(v==t)
                    return true;
                que.push(v);
            }
        }
    }
    return deep[t]==0?false:true;
}
int dfs(int u,int fl){
    if(u==t)
        return fl;
    int ans=0,x=0;
    for(int i=cur[u];~i;i=e[i].nextt){
        int v=e[i].v;
        if(e[i].w>0&&deep[v]==deep[u]+1){
            x=dfs(v,min(fl-ans,e[i].w));
            e[i].w-=x;
            e[i^1].w+=x;
            if(e[i].w)
                cur[u]=i;
            ans+=x;
            if(ans==fl)
                return ans;
        }
    }
    if(ans==0)
        deep[u]=0;
    return ans;
}
int dinic(int n){
    int ans=0;
    while(bfs()){
        //cout<<"!!"<<endl;
        for(int i=0;i<=n;i++)
            cur[i]=head[i];
        ans+=dfs(s,inf);
    }
    return ans;
}
int main(){
    init();
    int n=read(),m=read();
    //cout<<n<<"~~~~~"<<m<<endl;
    s=0,t=n*m+1;
    int ans=0;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            a[i][j]=read(),ans+=a[i][j];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if((i+j)&1)
                addedge((i-1)*m+j,t,a[i][j]);
            else
                addedge(s,(i-1)*m+j,a[i][j]);
        }
    }
    int sign=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(!((i+j)&1)){
                //cout<<"#####"<<sign++<<"########"<<endl;
                for(int k=0;k<4;k++){
                    int tx=i+gx[k];
                    int ty=j+gy[k];
                    if(tx>=1&&tx<=n&&ty>=1&&ty<=m){
                        addedge((i-1)*m+j,(i-1)*m+j+(tx-i)*m+(ty-j),inf);
                        //cout<<(i-1)*m+j+(tx-i)*m+(ty-j)<<endl;
                    }
                }
            }
                
        }
    }
    write(ans-dinic(t));
    return 0;
}
View Code

 

网络流24题!!!!

标签:tps   sizeof   ems   问题   取消   break   试题   答案   har   

原文地址:https://www.cnblogs.com/starve/p/10891619.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!