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***\n",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***\n",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\n",ra[i],rb[i],ra[i]+rb[i]);
130 else if(ref[e[j].v]==ra[i]-rb[i])
131 printf("%lld - %lld = %lld\n",ra[i],rb[i],ra[i]-rb[i]);
132 else if(ref[e[j].v]==ra[i]*rb[i])
133 printf("%lld * %lld = %lld\n",ra[i],rb[i],ra[i]*rb[i]);
134 break;
135 }
136 }
137 }
138 return 0;
139 }
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\n",ra[i],rb[i],ra[i]+rb[i]);
else if(ref[to[j]]==ra[i]-rb[i])
printf("%lld - %lld = %lld\n",ra[i],rb[i],ra[i]-rb[i]);
else if(ref[to[j]]==ra[i]*rb[i])
printf("%lld * %lld = %lld\n",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***\n",grap[x][i]);
if(grap[x][i] && !visit[i])
{
visit[i]=1;
//printf("%d %d %d****\n",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\n",ans,n,m);
if(ans!=n)
{
printf("impossible\n");
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\n",a,b,x);
if(x==a+b)
printf("%lld + %lld = %lld\n",a,b,x);
else if(x==a-b)
printf("%lld - %lld = %lld\n",a,b,x);
else if(x==a*b)
printf("%lld * %lld = %lld\n",a,b,x);
}
return 0;
} /*
4
1 5
3 3
4 5
-1 -6 */
Gym 101485 E Elementary Math 网络流 或者 二分图的更多相关文章
- hihoCoder 1393 网络流三·二分图多重匹配(Dinic求二分图最大多重匹配)
#1393 : 网络流三·二分图多重匹配 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 学校的秋季运动会即将开始,为了决定参赛人员,各个班又开始忙碌起来. 小Hi和小H ...
- 【BZOJ4429】[Nwerc2015] Elementary Math小学数学 最大流
[BZOJ4429][Nwerc2015] Elementary Math小学数学 Description Ellen给她的学生教小学数学.期末考试已经来临了.考试有n个题目,每一个题目学生们都要对一 ...
- 【邻接表+匈牙利算法模板】Elementary Math
http://acm.bnu.edu.cn/v3/external/gym/101485.pdf #include<bits/stdc++.h> using namespace std; ...
- Gym 101128F Sheldon Numbers(网络流)
[题目链接] http://codeforces.com/gym/101128/attachments [题目大意] 给出一张地图,分为高地和低地,高低地的交界线上划有红线, 现在要开小车跨过每条红线 ...
- poj 1274(网络流解二分图的最大匹配)
The Perfect Stall Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 22539 Accepted: 100 ...
- HDU 1083 网络流之二分图匹配
http://acm.hdu.edu.cn/showproblem.php?pid=1083 二分图匹配用得很多 这道题只需要简化的二分匹配 #include<iostream> #inc ...
- [HihoCoder1393]网络流三·二分图多重匹配
题目大意: 班级有$N$名学生,运动会有$M$项不同的比赛,第$i$项比赛每个班需要派出$m_i$名选手参加,编号为i的学生最多同时参加给定的$b_i$项比赛中的任意$a_i$项比赛.根据统计的结果, ...
- codeforce Gym 100203I I WIN (网络流)
把'I'拆成容量为1一条边,一个入点一个出点,入点和相邻的'W'连一条容量为1的边,出点和相邻的'N'连一条容量为1,所有的'W'和源点连一条容量为1边,所有的'N'和汇点连一条容量为1的边,表示只能 ...
- [HIHO1393]网络流三·二分图多重匹配
题目链接:http://hihocoder.com/problemset/problem/1393 把项目到汇点的边权值都加起来,跑完最大流后看是否最大流=权值和.如果等于权值和说明所有项目都有足够的 ...
随机推荐
- gin框架的路由源码解析
前言 本文转载至 https://www.liwenzhou.com/posts/Go/read_gin_sourcecode/ 可以直接去原文看, 比我这里直观 我这里只是略微的修改 正文 gin的 ...
- .net core 和 WPF 开发升讯威在线客服与营销系统:使用 WebSocket 实现访客端通信
本系列文章详细介绍使用 .net core 和 WPF 开发 升讯威在线客服与营销系统 的过程.本产品已经成熟稳定并投入商用. 在线演示环境:https://kf.shengxunwei.com 注意 ...
- 【Python】PDF转WORD
注意,下文中的PDF文档是纯文字格式,而且非扫描版的PDF文件. 如果是扫描版或者带有图片的.可能转起来会出现排版异常并且图片无法保存到.doc文件中. 正文开始: 需要安装依赖包 pdfminer3 ...
- SDUST数据结构 - 19级期末考试
判断题: 选择题: 函数题: 6-1 统计二叉树叶子结点个数: 题目: 裁判测试程序样例: #include <stdio.h> #include <stdlib.h> typ ...
- C# datagridview设置标题为汉语
正常情况下,在给datagridview绑定数据源之后,显示的是SQL语句中的栏位,如下 我们想让标题显示汉语,可以有一下两种方法 1.在SQL中设置列别名 SELECT TITLE AS '报警标题 ...
- USB限流IC,输入5V,输出5V,最大3A限流
USB限流芯片,5V输入,输出5V电压,限流值可以通过外围电阻进行调节,PWCHIP产品中可在限流范围0.4A-4.8A,并具有过压关闭保护功能. 过压关闭保护: 如芯片:PW1555,USB我们一半 ...
- 《awk中文手册》-本人参考官方手册翻译
01. 简介 AWK是一个文本(面向行和列)处理工具,同时它也是一门脚本语言. AWK其名称得自于它的创始人 Alfred Aho .Peter Weinberger 和 Brian Kernigha ...
- 全栈性能测试修炼宝典-JMeter实战笔记(一)
了解性能测试 性能测试不仅能够定位.分析问题,还要把握系统性能变化趋势:性能测试工程师能够帮助解决性能问题,搞定测试过程中的各种不合理配置,给出专业的优化建议. 第一章 性能方向职业发展 软件测试职业 ...
- DP 状态 DP 转移方程 动态规划解题思路
如何学好动态规划(2) 原创 Gene_Liu LeetCode力扣 今天 算法萌新如何学好动态规划(1) https://mp.weixin.qq.com/s/rhyUb7d8IL8UW1IosoE ...
- 避免重复提交?分布式服务的幂等性设计! 架构文摘 今天 点击蓝色“架构文摘”关注我哟 加个“星标”,每天上午 09:25,干货推送! 来源:https://www.cnblogs.com/QG-whz/p/10372458.html 作者:melonstreet
避免重复提交?分布式服务的幂等性设计! 架构文摘 今天 点击蓝色"架构文摘"关注我哟 加个"星标",每天上午 09:25,干货推送! 来源:h ...