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

*/
原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/13940190.html