传送门

来源:2019 年“浪潮杯”第十届山东省 ACM 省赛

题意:

  对于一个包含n个数的(n为奇数)序列val[ ],排序后的 val[ (n+1) / 2 ] 定义为 median;

  有 n 个数,并有 m 组关系,对于第 i 组关系 ai,bi 代表第 val[ai] > val[bi];

  但并没有给出具体的数值;

  输出一个包含 n 个元素的数组 s[ ] ;

  让你判断第 i 个数 val[ i ]是可能为中位数,如果是,第 i 位为 1;

  如果不是,第 i 位为 0;

  输出 n 个数,其中第 i 个数为 0 或 1,含义如上;

题解:

  首先,特判两种情况:

    ①ai = bi

    ②给出的 m 个关系有环;

  对于这两种情况,输出 n 个 0;

  除了这两种情况外,就是一个有向无环图;

  如何判断第 i 位是否为 median 呢?

  搜索:

  正向搜索比第 i 个数小的数的总个数 tot1;

  反向搜索比第 i 个数大的数的总个数 tot2;

  那么,还剩下 res = n-(tot1+tot2+1) 个数;

  如果 res ≥ |tot1-tot2|,那么第 i 个数就是中位数;

AC代码:

 #include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
const int maxn=1e4+; int n,m;
int num;
int head[maxn];
bool vis[];
bool isCir;
char s[];
struct Edge
{
int to;
int next;
}G[maxn<<];
void addEdge(int u,int v)
{
G[num]={v,head[u]};
head[u]=num++;
}
struct SCC
{
vector<int >vs;
void DFS(int u)
{
vis[u]=true;
for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
if((i&) || vis[v])
continue;
DFS(v);
}
vs.push_back(u);
}
void RDFS(int u,int k)
{
vis[u]=true;
for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
if(!(i&) || vis[v])
continue;
RDFS(v,k);
}
}
int scc()
{
vs.clear();
mem(vis,false);
for(int i=;i <= n;++i)
if(!vis[i])
DFS(i); int k=;
mem(vis,false);
for(int i=vs.size()-;i >= ;--i)
if(!vis[vs[i]])
RDFS(vs[i],++k);
return k;
}
}_scc;
int DFS(int u)///正向搜索比第 i 个数小的数
{
int ans=;
vis[u]=true;
for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
if((i&) || vis[v])
continue;
ans += DFS(v);
}
return ans;
}
int RDFS(int u)///反向搜索比第 i 个数大的数
{
int ans=;
vis[u]=true;
for(int i=head[u];~i;i=G[i].next)
{
int v=G[i].to;
if(!(i&) || vis[v])
continue;
ans += RDFS(v);
}
return ans;
}
bool isSat(int u)
{
mem(vis,false);
int tot1=DFS(u)-;
mem(vis,false);
int tot2=RDFS(u)-; return abs(tot1-tot2) <= (n-tot1-tot2-) ? true:false;
}
char *Solve()
{
mem(s,'');
s[n]='\0';
int k=_scc.scc();///强连通分量分解判断是否含有环
if(k < n)
isCir=true;
if(isCir)
return s; for(int i=;i <= n;++i)
if(isSat(i))///判断第 i 个数是否为median
s[i-]='';
return s;
}
void Init()
{
num=;
mem(head,-);
isCir=false;
}
int main()
{
// freopen("C:\\Users\\hyacinthLJP\\Desktop\\in&&out\\contest","r",stdin);
int test;
scanf("%d",&test);
while(test--)
{
scanf("%d%d",&n,&m);
Init();
for(int i=;i <= m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
if(u == v)
isCir=true;
addEdge(u,v);///正向边
addEdge(v,u);///反向边
}
printf("%s\n",Solve());
}
return ;
}

凯少思路:

如果 tot1 ≤ n/2 && tot2 ≤ n/2 返回 true;

在返回结果的时候改成这句也可以,我的判断方法也对;

代码:

 #include <iostream>
#include <vector>
#include <cstring>
#include <queue>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
using namespace std;
const int ss = ;
int v1[ss];
int v2[ss];
int dfn[ss];
int low[ss];
int vis[ss];
int son1[ss];
int son2[ss];
int pot[ss];
vector < int >G[ss];
vector < int >P[ss];
stack < int >S;
int scc, tim, n, m, t;
void start()
{
memset(v1, , sizeof(v1));
memset(v2, , sizeof(v2));
memset(dfn, , sizeof(dfn));
memset(vis, , sizeof(vis));
memset(low, , sizeof(low));
memset(pot, , sizeof(pot));
memset(son1, , sizeof(son1));
memset(son2, , sizeof(son2));
for (int i = ; i <= n; i++)
{
G[i].clear();
P[i].clear();
}
while (!S.empty())
S.pop();
scc = tim = n = m = ;
}
void tar(int u)
{
int v;
low[u] = dfn[u] = ++tim;
S.push(u);
vis[u] = ;
for (int i = ; i < G[u].size(); i++)
{
v = G[u][i];
if (!dfn[v])
{
tar(v);
if (low[u] > low[v])
low[u] = low[v];
} else if (vis[v] && low[u] > dfn[v])
low[u] = dfn[v];
}
if (low[u] == dfn[u])
{
scc++;
do
{
v = S.top();
S.pop();
vis[v] = ;
} while (v != u);
}
}
int dfs1(int x)
{
v1[x] = ;
for (int i = ; i < G[x].size(); i++)
{
if (!v1[G[x][i]])
son1[x] += dfs1(G[x][i]);
}
return son1[x] + ;
}
int dfs2(int x)
{
v2[x] = ;
for (int i = ; i < P[x].size(); i++)
{
if (!v2[P[x][i]])
son2[x] += dfs2(P[x][i]);
}
return son2[x] + ;
}
void print(int x, int p)
{
for (int i = ; i <= n; i++)
{
if (i == p)
printf("");
else
printf("");
}
printf("\n");
}
int main()
{
cin >> t;
while (t--)
{
start();
int ok = ;
cin >> n >> m;
for (int i = ; i <= m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
if (a == b)
ok = ;
G[a].push_back(b);
P[b].push_back(a);
}
if (!ok)
{
print(n, );
} else
{
for (int i = ; i <= n; i++)
if (!dfn[i])
tar(i);
if (scc != n)
print(n, );
else
{
int point = ;
for (int i = ; i <= n; i++)
{
dfs1(i);
dfs2(i);
if ((son1[i] <= (n / )) && (son2[i] <= (n / )))
pot[i] = ;
memset(son1, , sizeof(son1));
memset(son2, , sizeof(son2));
memset(v1, , sizeof(v1));
memset(v2, , sizeof(v2));
}
for (int i = ; i <= n; i++)
cout << pot[i];
cout << "\n";
}
}
}
return ;
}

因为 n 很小,所以对每个点跑两次DFS并不会超时;

但,如果 n 大了呢,那制定不能每个点跑两次DFS了,那该肿么办呢?

本蒟蒻还没想出来~~~~~~~~

据说,此题正解为求解两次拓扑序;

https://paste.ubuntu.com/p/xXxYdnDRBV/

zoj 4124 "Median" (思维?假的图论?)的更多相关文章

  1. ZOJ 4124 拓扑排序+思维dfs

    ZOJ - 4124Median 题目大意:有n个元素,给出m对a>b的关系,问哪个元素可能是第(n+1)/2个元素,可能的元素位置相应输出1,反之输出0 省赛都过去两周了,现在才补这题,这题感 ...

  2. ZOJ 3829 贪心 思维题

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3829 现场做这道题的时候,感觉是思维题.自己智商不够.不敢搞,想着队友智商 ...

  3. D - The Lucky Week ZOJ - 3939 (思维)

    题目链接: D - The Lucky Week  ZOJ - 3939 题目大意:幸运的星期指,星期一为每个月的1 or 11 or 21号.给出第一个幸运星期的时间,问从当前的日起开始.第n个的日 ...

  4. Beauty of Array ZOJ - 3872(思维题)

    Edward has an array A with N integers. He defines the beauty of an array as the summation of all dis ...

  5. ACM-ICPC 2018 青岛赛区现场赛 D. Magic Multiplication && ZOJ 4061 (思维+构造)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4061 题意:定义一个长度为 n 的序列 a1,a2,..,an ...

  6. JOISC2014 Day2 E "交朋友" (思维+假的SCC)

    传送门 题目描述 你是活跃在历史幕后的一名特工,为了世界和平而夜以继日地努力着. 这个世界有N个国家,编号为1..N; 你的目的是在这N个国家之间建立尽可能多的友好关系. 你为了制定一个特工工作的计划 ...

  7. ZOJ Monthly, January 2018 训练部分解题报告

    A是水题,此处略去题解 B - PreSuffix ZOJ - 3995 (fail树+LCA) 给定多个字符串,每次询问查询两个字符串的一个后缀,该后缀必须是所有字符串中某个字符串的前缀,问该后缀最 ...

  8. 怎么用MindManager制作议论文思维导图

    大家都写过作文吧,做小学到高考到大学,这是谁也摆脱不了的,但是大家写作文会提前把自己的思路整理出来吗?让自己行文更为顺畅,作文更为流利吗?特别是关于议论文,一直是高考写作的一个重点篇目,写好议论文,就 ...

  9. [NOIP 2005] 运输计划

    link 这是一道假的图论 思维难度很低,代码量偏高 就是一道板子+二分 树上差分就AC了 注意卡常即可 二分枚举答案x,为时间长度 将每一个长度大于x的计划链长记录下来(有几个,总需要减少多少长度) ...

随机推荐

  1. PHP学习(运算符)

    PHP运算符一般分为算术运算符.赋值运算符.比较运算符.三元运算符.逻辑运算符.字符串连接运算符.错误控制运算符. 算术运算符 主要是用于进行算术运算的,例如:加法运算.减法运算.乘法运算.除法运算 ...

  2. BOM的对象总结(location,screen,navigator,history)

    location对象 专门保存当前窗口正在打开的url的对象. 常用的属性有: location.href 保存了完整的url:这种方式做常用 在当前窗口打开: location.href=新url ...

  3. 【巨人的步伐以及人类的进击】BSGS algorithm

    原问题 求ax≡b(mod p)的最小正整数解. 解法 实际上是以空间换取时间的算法. 先用散列表把 ai (i∈[0,p√)) 都储存起来. 然后再从小到大枚举 j (j∈[0,p√)) ,在散列表 ...

  4. 解决Dynamic Web Module 3.0 requires Java 1.6 or newer.问题

    在项目的pom.xml的<build></build>标签中增加: <plugins>       <plugin>           <gro ...

  5. LocalDateTime计算时间差

    LocalDateTime 为java8的新特性之一 LocalDateTime.now() 获得当前时间 java.time.Duration duration = java.time.Durati ...

  6. UIScrollView 实践经验

    UIScrollView(包括它的子类 UITableView 和 UICollectionView)是 iOS 开发中最常用也是最有意思的 UI 组件,大部分 App 的核心界面都是基于三者之一或三 ...

  7. java中URLEncode和URLDecode

    URLEncode和URLDecode用于完成普通字符串和 application/x-www-from-urlencoded MIME字符串之间的相互转化 如果传递的字符串中包含非西欧字符的字符串, ...

  8. 【转载】STL 的 erase() 陷阱-迭代器失效总结

    下面材料整理自Internet&著作. TL中的容器按存储方式分为两类,一类是按以数组形式存储的容器(如:vector .deque):另一类是以不连续的节点形式存储的容器(如:list.se ...

  9. sql —— top

    用于规定要返回的记录的数目 原表: 我们如果只想看前三个学生信息的话:

  10. MAYA安装失败怎样卸载重新安装MAYA,解决MAYA安装失败的方法总结

    技术帖:MAYA没有按照正确方式卸载,导致MAYA安装失败.楼主也查过网上关于如何解决MAYA安装失败的一些文章,是说删除几个MAYA文件和MAYA软件注册表就可以解决MAYA安装失败的问题,实际的情 ...