• Gym 101485 E Elementary Math 网络流 或者 二分图


    题意:

    输入一个n,后面输入n行,每一行两个数a、b。你可以对a、b进行三种操作:+、-、*

    你需要保证对每一行a、b选取一个操作得到一个结果

    你要保证这n行每一个式子选取的操作之后得到的结果都不一样。如果找不到就输出impossible

    Sample Input 1 

    1 4

    1 5

    3 3

    4 5

    -1 -6

    Sample Output

    1 + 5 = 6

    3 * 3 = 9

    4 - 5 = -1

    -1 - -6 = 5
    Sample Input 2

    2 4

    -4 2

    -4 2

    -4 2

    -4 2

    Sample Output

    impossible

    题解:

    网络流跑一边最大流就可以了

    首先建一个汇点st,然后让st点和n个式子相连,把这n个式子看成一个点,然后一个式子对应三个结果,我们分别对着三个结果看成一个点,然后连线。之后把所有的结果点连接到一个尾点en

    然后就是路径输出就行了,如果一个路径有流量,那么这个路径的流量信息肯定有改变,就判断这一点就可以输出路径

    建图其实很简单,这里主要说一下不同网络流的复杂度

    简单总结 

    FF算法: 利用dfs实现,时间复杂度O(V*E^2)

    EK算法:利用bfs实现,时间复杂度O(V*E^2)

    Dinic算法:递归实现,时间复杂度O(V^2*E)

    SAP算法:时间复杂度O(V^2*E)但是加上弧优化和间隙优化之后时间复杂度非常可观

    我以前认为点的数量肯定比边的数量小,所以dinic算法复杂度最小,所以就只记住了一个dinic算法

    但是这一道题使用dinic算法就TLE了

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <iostream>
      4 #include <queue>
      5 #include <map>
      6 #define mem(a,b) memset(a,b,sizeof(a))
      7 using namespace std;
      8 typedef long long ll;
      9 const int maxn=8000;
     10 queue<int> q;
     11 int n,m,cnt,st,en,ans;
     12 ll ref[10010],ra[2510],rb[2510];
     13 int head[maxn],dis[maxn],cur[maxn];
     14 map<ll,int> r;
     15 struct edge
     16 {
     17     int v,next,c,flow;
     18 } e[maxn<<2];
     19 void add_edge(int x,int y,int z)
     20 {
     21     e[cnt].v=y;
     22     e[cnt].c=z;
     23     e[cnt].flow=0;
     24     e[cnt].next=head[x];
     25     head[x]=cnt++;
     26 
     27     e[cnt].v=x;
     28     e[cnt].c=0;
     29     e[cnt].flow=0;
     30     e[cnt].next=head[y];
     31     head[y]=cnt++;
     32 }
     33 int bfs()
     34 {
     35     mem(dis,0);
     36     dis[st]=1;
     37     queue<int>r;
     38     r.push(st);
     39     while(!r.empty())
     40     {
     41         int x=r.front();
     42         r.pop();
     43         //printf("%d***
    ",x);
     44         for(int i=head[x]; i!=-1; i=e[i].next)
     45         {
     46             int v=e[i].v;
     47             if(!dis[v] && e[i].c>e[i].flow)
     48             {
     49                 //printf("%d***
    ",v);
     50                 dis[v]=dis[x]+1;
     51                 r.push(v);
     52             }
     53         }
     54     }
     55     return dis[en];
     56 }
     57 int dinic(int s,int limit)
     58 {
     59     if(s==en || !limit) return limit;
     60     int ans=0;
     61     for(int &i=cur[s]; i!=-1; i=e[i].next)
     62     {
     63         int v=e[i].v,feed;
     64         if(dis[v]!=dis[s]+1) continue;
     65         feed=dinic(v,min(limit,e[i].c-e[i].flow));
     66         if(feed)
     67         {
     68             e[i].flow+=feed;
     69             e[i^1].flow-=feed;
     70             limit-=feed;
     71             ans+=feed;
     72             if(limit==0) break;
     73         }
     74     }
     75     if(!ans) dis[s]=-1;
     76     return ans;
     77 }
     78 inline int rd()
     79 {
     80     int ret=0,f=1;
     81     char gc=getchar();
     82     while(gc<'0'||gc>'9')
     83     {
     84         if(gc=='-')    f=-f;
     85         gc=getchar();
     86     }
     87     while(gc>='0'&&gc<='9')    ret=ret*10+(gc^'0'),gc=getchar();
     88     return ret*f;
     89 }
     90 int main()
     91 {
     92     n=m=rd(),st=0;
     93     int i,j;
     94     memset(head,-1,sizeof(head));
     95     for(i=1; i<=n; i++)
     96     {
     97         ra[i]=rd(),rb[i]=rd();
     98         if(!r[ra[i]+rb[i]])    r[ra[i]+rb[i]]=++m,ref[m]=ra[i]+rb[i];
     99         if(!r[ra[i]-rb[i]])    r[ra[i]-rb[i]]=++m,ref[m]=ra[i]-rb[i];
    100         if(!r[ra[i]*rb[i]])    r[ra[i]*rb[i]]=++m,ref[m]=ra[i]*rb[i];
    101         add_edge(i,r[ra[i]+rb[i]],1);
    102         add_edge(i,r[ra[i]-rb[i]],1);
    103         add_edge(i,r[ra[i]*rb[i]],1);
    104         add_edge(st,i,1);
    105     }
    106     en=m+1;
    107     for(i=n+1; i<=m; i++)    add_edge(i,en,1);
    108     int ans=0;
    109     while(bfs())
    110     {
    111         for(int i=0; i<=en+1; ++i)
    112         {
    113             cur[i]=head[i];
    114         }
    115         ans+=dinic(st,1);
    116     }
    117     if(ans!=n)
    118     {
    119         printf("impossible");
    120         return 0;
    121     }
    122     for(i=1; i<=n; i++)
    123     {
    124         for(j=head[i]; j!=-1; j=e[j].next)
    125         {
    126             if(e[j].flow>0 && e[j].v!=st)
    127             {
    128                 if(ref[e[j].v]==ra[i]+rb[i])
    129                     printf("%lld + %lld = %lld
    ",ra[i],rb[i],ra[i]+rb[i]);
    130                 else if(ref[e[j].v]==ra[i]-rb[i])
    131                     printf("%lld - %lld = %lld
    ",ra[i],rb[i],ra[i]-rb[i]);
    132                 else if(ref[e[j].v]==ra[i]*rb[i])
    133                     printf("%lld * %lld = %lld
    ",ra[i],rb[i],ra[i]*rb[i]);
    134                 break;
    135             }
    136         }
    137     }
    138     return 0;
    139 }
    View Code

    AC代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #include <map>
    using namespace std;
    typedef long long ll;
    queue<int> q;
    int n,m,cnt,st,en,ans;
    ll ref[10010],ra[2510],rb[2510];
    int to[100000],nxt[100000],head[10010],val[100000],dis[10010];
    map<ll,int> r;
    
    inline void add(int a,int b,int c)
    {
        to[cnt]=b,val[cnt]=c,nxt[cnt]=head[a],head[a]=cnt++;
        to[cnt]=a,val[cnt]=0,nxt[cnt]=head[b],head[b]=cnt++;
    }
    int dfs(int x,int mf)
    {
        if(x==en)    return mf;
        int i,k,temp=mf;
        for(i=head[x]; i!=-1; i=nxt[i])  
            if(dis[to[i]]==dis[x]+1&&val[i])
            {
                k=dfs(to[i],min(temp,val[i]));
                if(!k)  dis[to[i]]=0;
                temp-=k,val[i]-=k,val[i^1]+=k;
                if(!temp)   break;
            }
        return mf-temp;
    }
    int bfs()
    {
        while(!q.empty())   q.pop();
        memset(dis,0,sizeof(dis));
        q.push(st),dis[st]=1;
        int i,u;
        while(!q.empty())
        {
            u=q.front(),q.pop();
            for(i=head[u]; i!=-1; i=nxt[i])  if(!dis[to[i]]&&val[i])
                {
                    dis[to[i]]=dis[u]+1;
                    if(to[i]==en)    return 1;
                    q.push(to[i]);
                }
        }
        return 0;
    }
    inline int rd()
    {
        int ret=0,f=1;
        char gc=getchar();
        while(gc<'0'||gc>'9')
        {
            if(gc=='-')    f=-f;
            gc=getchar();
        }
        while(gc>='0'&&gc<='9')   ret=ret*10+(gc^'0'),gc=getchar();
        return ret*f;
    }
    int main()
    {
        n=m=rd(),st=0;
        int i,j;
        memset(head,-1,sizeof(head));
        for(i=1; i<=n; i++)
        {
            ra[i]=rd(),rb[i]=rd();
            if(!r[ra[i]+rb[i]])
                r[ra[i]+rb[i]]=++m,ref[m]=ra[i]+rb[i];
            if(!r[ra[i]-rb[i]])
                r[ra[i]-rb[i]]=++m,ref[m]=ra[i]-rb[i];
            if(!r[ra[i]*rb[i]])
                r[ra[i]*rb[i]]=++m,ref[m]=ra[i]*rb[i];
            add(i,r[ra[i]+rb[i]],1);
            add(i,r[ra[i]-rb[i]],1);
            add(i,r[ra[i]*rb[i]],1);
            add(st,i,1);
        }
        en=m+1;
        for(i=n+1; i<=m; i++)  add(i,en,1);
        while(bfs())
            ans+=dfs(st,1<<30);
        if(ans!=n)
        {
            printf("impossible");
            return 0;
        }
        for(i=1; i<=n; i++)
        {
            for(j=head[i]; j!=-1; j=nxt[j])
            {
                if(!val[j])
                {
                    if(ref[to[j]]==ra[i]+rb[i])
                        printf("%lld + %lld = %lld
    ",ra[i],rb[i],ra[i]+rb[i]);
                    else if(ref[to[j]]==ra[i]-rb[i])
                        printf("%lld - %lld = %lld
    ",ra[i],rb[i],ra[i]-rb[i]);
                    else if(ref[to[j]]==ra[i]*rb[i])
                        printf("%lld * %lld = %lld
    ",ra[i],rb[i],ra[i]*rb[i]);
                }
            }
        }
        return 0;
    }

    二分图题解:

    就是把n个式子看成n个点,把n个式子对应的三个结果看成3*n个点

    二分图匹配就行

    代码:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #include <map>
    using namespace std;
    typedef long long ll;
    const int maxn=7500+10;
    const int INF=0x3f3f3f3f;
    const long long ll_INF=0x3f3f3f3f3f3f3f3fll;
    ll match[maxn],visit[maxn],n,m,grap[2505][maxn],link[maxn];
    map<ll,ll>r;
    ll dfs_solve(ll x)
    {
        for(ll i=1; i<=m; ++i)
        {
            //printf("%d***
    ",grap[x][i]);
            if(grap[x][i] && !visit[i])
            {
                visit[i]=1;
                //printf("%d %d %d****
    ",x,i,match[i]);
                if(match[i]==0 || dfs_solve(match[i]))
                {
                    match[i]=x;
                    link[x]=i;
                    return 1;
                }
            }
        }
        return 0;
    }
    ll hungran()
    {
        memset(match,0,sizeof(match));
        ll sum=0;
        for(ll i=1; i<=n; ++i)
        {
            memset(visit,0,sizeof(visit));
            sum+=dfs_solve(i);
        }
        return sum;
    }
    ll que[maxn];
    struct shudui
    {
        ll a,b;
    } w[2505];
    int main()
    {
        scanf("%lld",&n);
        m=0;
        for(ll i=1; i<=n; ++i)
        {
            ll a,b;
            scanf("%lld%lld",&a,&b);
            w[i].a=a;
            w[i].b=b;
            if(r[a*b]==0)
            {
                r[a*b]=++m;
                que[m]=a*b;
            }
            grap[i][r[a*b]]=1;
            if(r[a+b]==0)
            {
                r[a+b]=++m;
                que[m]=a+b;
            }
            grap[i][r[a+b]]=1;
            if(r[a-b]==0)
            {
                r[a-b]=++m;
                que[m]=a-b;
            }
            grap[i][r[a-b]]=1;
        }
        ll ans=hungran();
        //printf("%lld***%lld %lld
    ",ans,n,m);
        if(ans!=n)
        {
            printf("impossible
    ");
            return 0;
        }
        for(ll i=1; i<=n; ++i)
        {
            ll x=que[link[i]];
            ll a=w[i].a;
            ll b=w[i].b;
            //printf("%lld %lld %lld
    ",a,b,x);
            if(x==a+b)
                printf("%lld + %lld = %lld
    ",a,b,x);
            else if(x==a-b)
                printf("%lld - %lld = %lld
    ",a,b,x);
            else if(x==a*b)
                printf("%lld * %lld = %lld
    ",a,b,x);
        }
        return 0;
    }
    
    /*
    4
    1 5
    3 3
    4 5
    -1 -6
    
    */
  • 相关阅读:
    Java——HashSet和TreeSet的区别
    TreeSet和TreeMap不能存放重复元素?能不能存放null?其实不是这样的——灵活的二叉树
    Java 数组元素逆序Reverse的三种方式
    Java开发中使用sort排序
    Android Studio导入第三方库的三种方法
    Android下拉涮新第三方通用控件
    手把手教你MyEclipseUML建模(下)
    手把手教你MyEclipseUML建模(上)
    java enum(枚举)使用详解 + 总结
    翻译学python---《Learn Python the hard Way》---第一章 绪论
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/13940190.html
Copyright © 2020-2023  润新知