题目链接:点击这里

题意:给定n个人之间的强壮关系(没有传递性),分成两个组,首先判断每一组是否能够通过某种排列使得前面的人都比后面的人强壮。如果可以,最多能从2组中选几个人到1组使得1组通过排列仍然使得前面的人都比后面的人强壮。

因为是个竞赛图,只要没有环就行(DAG),所以直接拓扑如果出队列数刚好等于节点数就可以,在拓扑的时候顺便记下拓扑序给先前的两组按照拓扑序排完。至于最多能够扔过去的点,本来想的是贪心,一个点能够扔到1组当且仅当能打败他的点的最大拓扑序小于他能打败的最小拓扑序。但是有可能把一个点扔过去后导致更多的点扔不过去。所以考虑第二组每个点能够放在第一组的位置,然后第二组所有的点就都有一个位置了,然后求一次LIS就是最多的点数。
O(n2n^2)蜜汁超时,加了输入挂和nlgn的LIS才过=。=

#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <set>
using namespace std;
#define maxn 1005
#define maxm 2000005int n, m;
int g[maxn][maxn];
struct E {int v, next;
}edge[maxm];
int head[maxn], cnt;
bool vis[maxn];
int a[maxn], b[maxn];
int ida[maxn], idb[maxn];
int degree[maxn];//入度
struct node {int x, y;bool operator < (const node &a) const {return x < a.x || (x == a.x && y < a.y);}
};
set <node> gg;void add_edge (int u, int v) {edge[cnt].v = v, edge[cnt].next = head[u], head[u] = cnt++;
}int q[maxn];
bool topo (int *a, int n, int *id) {int root = 0;for (int i = 1; i <= n; i++) {if (!degree[a[i]]) {root = a[i];break;}}int num = 0;if (!root)return 0;num++;int tou = 0, wei = 0;q[wei++] = root;id[root] = 1;int index = 1;while (tou < wei) {int u = q[tou++];for (int i = head[u]; i != -1; i = edge[i].next) {int v = edge[i].v; degree[v]--;if (!degree[v]) {q[wei++] = v;num++;id[v] = ++index;}}}if (num < n)return 0;return 1;
}bool cmp1 (const int &x, const int &y) {return ida[x] < ida[y];
}
bool cmp2 (const int &x, const int &y) {return idb[x] < idb[y];
}int h[maxn], dp[maxn];
#define INF 10000000
int LIS (int *a, int n) {if (!n)return 0;int ans = 0;for (int i = 1; i <= n; i++) h[i] = INF;for (int i = 1; i <= n; i++) {int k = lower_bound (h+1, h+1+n, a[i])-h;ans = max (ans, k);h[k] = a[i];}return ans;
}int x[maxn];
void solve () {//T2memset (head, -1, (n+10) * sizeof (int));memset (degree, 0, (n+10) * sizeof (int));cnt = 0;for (int i = 1; i <= n-m; i++) {for (int j = i+1; j <= n-m; j++) {if (g[b[i]][b[j]]) add_edge (b[i], b[j]), degree[b[j]]++;else add_edge (b[j], b[i]), degree[b[i]]++;}}if (!topo (b, n-m, idb)) {printf ("NO\n");return ;}//T1for (int i = 1; i <= m; i++) {for (int j = i+1; j <= m; j++) {if (g[a[i]][a[j]]) add_edge (a[i], a[j]), degree[a[j]]++;else add_edge (a[j], a[i]), degree[a[i]]++;}}if (!topo (a, m, ida)) {printf ("NO\n");return ;}printf ("YES ");gg.clear ();sort (a, a+m, cmp1);sort (b, b+n-m, cmp2);for (int i = 1; i <= n-m; i++) {int pos1 = 0, pos2 = 0;int Min = 1000000, Max = 0;//连向它的最大的 它连向的最小的for (int u = 1; u <= m; u++) {if (g[a[u]][b[i]]) {if (ida[a[u]] > Max) {Max = ida[a[u]];pos1 = a[u];}}else {    if (ida[a[u]] < Min) {Min = ida[a[u]];pos2 = a[u];}}}if (Min > Max) {gg.insert ((node) {Max, idb[b[i]]});}}//LISint len = 0;for (set<node>::iterator it = gg.begin (); it != gg.end (); it++) {x[++len] = it->y;}printf ("%d\n", LIS (x, len));
}int scan () {char ch = ' ';while (ch < '0'|| ch > '9') ch = getchar ();int x = 0;while (ch <= '9' && ch >= '0') x = x*10+ch-'0', ch = getchar ();return x;
}int main () {while (scanf ("%d%d", &n, &m) == 2 && n+m) {for (int i = 1; i <= n; i++) {for (int j = 1; j <= n; j++) {g[i][j] = scan ();}vis[i] = 0;}for (int i = 1; i <= m; i++) {a[i] = scan ();vis[a[i]] = 1;}int cnt = 0;for (int i = 1; i <= n; i++) if (!vis[i]) {b[++cnt] = i;}solve ();}return 0;
}
/*
10 5
0 1 1 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1 1
0 0 0 1 1 1 1 1 1 1
0 0 0 0 1 1 1 1 1 1
0 0 0 0 0 1 1 1 1 1
0 0 0 0 0 0 1 1 1 1
0 0 0 0 0 0 0 1 1 1
0 0 0 0 0 0 0 0 1 1
0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0
1 3 5 7 910 3
0 1 1 1 1 1 1 1 1 1
0 0 1 1 1 1 1 1 1 1
0 0 0 1 1 1 1 1 1 1
0 0 0 0 1 1 1 1 1 1
0 0 0 0 0 1 1 1 1 1
0 0 0 0 0 0 1 1 1 1
0 0 0 0 0 0 0 1 1 1
0 0 0 0 0 0 0 0 1 1
0 0 0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0 0 0
10 9 8
*/

HDU 5811 (拓扑排序 LIS)相关推荐

  1. HDU 4857 拓扑排序 优先队列

    n个数,已经有大小关系,现给m个约束,规定a在b之前,剩下的数要尽可能往前移.输出序列 大小关系显然使用拓扑结构,关键在于n个数本身就有大小关系,那么考虑反向建图,优先选择值最大的入度为零的点,这样得 ...

  2. hdu 1811(拓扑排序+并查集)

    解题思路: 拓扑排序的两个性质: ①如果一次入队入度为零的点大于1则说明拓扑排序序列不唯一 ②如果排序的总个数小于给定的个数,则说明存在回路 可以先把"="的两个数用并查集放在一个 ...

  3. HDU 2647 拓扑排序

    题意:每个人的工资至少888,然后有m个条件,前者比后者要多.求最少工资. 分析: 最开始的开邻接矩阵的肯定超时,如果dfs,会出现由于刚开始不是从入度为0的点出发,后期修改不了.比较麻烦. 正确方式 ...

  4. hdu 5438 Ponds 拓扑排序

    Ponds Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/contests/contest_showproblem ...

  5. HDU 3342 Legal or Not(拓扑排序判断成环)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3342 题目大意:n个点,m条有向边,让你判断是否有环. 解题思路:裸题,用dfs版的拓扑排序直接套用即 ...

  6. HDU 1811 Rank of Tetris(并查集按秩合并+拓扑排序)

    Rank of Tetris Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) T ...

  7. HDU 2647 Reward (拓扑排序)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2647 题意是给你n点m条有向边,叶子点(出度为0)上的值为888,父亲点为888+1,依次计算... ...

  8. HDU 2647 Reward 拓扑排序

    http://acm.hdu.edu.cn/showproblem.php?pid=2647 题意: 输入N和M代表N个人和M组数据,M组数据中的A和B代表A的工资要比B的工资高,底薪是(888元), ...

  9. hdu 4857 逃生 拓扑排序

    逃生 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=4857 Description 糟糕的事情发生啦,现在大家都忙着逃命.但是逃命的通道很窄,大家只 ...

最新文章

  1. 崛起的Python,真的影响了76万人?
  2. 以后配置Nginx 用这款神器!
  3. HTML5学习笔记(十四):变量作用域
  4. 去除警告,打电话,发信息,应用程序之间跳转,打印沙盒路径,字符串名字转换方法,包装导航控制器等的代码...
  5. ble之gatt server
  6. boost::fusion::reverse_view用法的测试程序
  7. 智能制作,是我们改变时代的机会——阿里云视频云的理想与未来
  8. [阅读记录]《新ABS_Guide_cn.txt》shell脚本的编写
  9. opensuse ati 显卡驱动安装
  10. SQL的简单增、删、改
  11. python文件是否存在_Python判断文件是否存在的三种方法
  12. 计算机输出科学计数法,C语言里要对输出的结果用科学计数法表示保留三位有效数字应该怎么写啊?...
  13. 制造业智能工厂车间无线工业物联网解决方案
  14. python命名空间与作用域
  15. 路由器常见的第三方系统( OpenWRT,LEDE,PandoraBox,Gargoyle | ASUSWrt,Merlin,Padavan | DD-WRT | Tomato )
  16. 中国国内驾照在韩国换驾照的经过
  17. 程序员去国企面试,跟领导谈完技术感叹:给再多的工资也不考虑
  18. MongoDB语法案例
  19. Cannot start compiler
  20. iwork8 Android86,酷比魔方(CUBE)IWORK8 U80GT平板电脑整体评测-ZOL中关村在线

热门文章

  1. 关于U盘中的文件全部变成快捷方式的解决办法
  2. Python将阿拉伯数字转化为中文大写
  3. 微软服务器改dns,Win10修改微软DNS的方法!
  4. 人工智能:深度学习算法及应用——简单理解CNN卷积神经网络并python实现(带源码)
  5. 通过OpenSSL解析X509证书基本项
  6. 《新理解矩阵1》:矩阵是什么?
  7. 使用magick 遇到 convert: Non-conforming drawing primitive definition `text'错误的解决办法...
  8. Failed resolution of: Landroid/webkit/TracingController;
  9. html5/css登录注册网页模板
  10. 【5G模组】讨论RSSI,RSRP,RSRQ and SINR