Coder-Strike 2014 - Round 1__Giving Awards

题目链接

  • 题意:

    给定n个点,m个限制条件。每个限制条件表示为a,b,给定一个序列,使得b不在a后边

  • 分析:

    第一次看到这个题目就想到了拓扑排序。。。看来理解还不是很到位。拓扑排序给定的是一个偏序关系,而这个题目的关系不是偏序关系。

    题目的点数和边数都限定的十分完美。。本来想建立一个“可行图”,a->b表示b可以在a的后边。但是这样建边会超内存。。

    (看的题解的想法)考虑一下,加入当前已经排好了n个数:a1、a2....ak,那么要添加ak+1时,先放到ak后边,如果有这个限制(ak+1不能放到ak后边),那么就将ak+1前移,一直重复,直到ak+1到第一个位置或者不冲突为止。这样的处理方式就是对于限制a->b,建图b->a,对于一个点,搜索的时候找到所有不能在它前边的点,放到当前点的后边即可。

    这个题目其实也可以算是一种构造法,因为满足题目的答案有很多,只要按照一个规则能找到答案即可。那么我们就考虑题目的限制来作为规则的生成依据。

    1:扩展可行解集。如上述过程

    2:对于一个最终解集,找规律。最后,序列中的相邻两个人a、b,肯定没有a->b,有两种情况:1.没有边  2.有b->a

const int MAXN = 100001;

vector<int> G[MAXN], ans;
bool vis[MAXN];
void dfs(int u)
{
    vis[u] = true;
    REP(i, G[u].size())
    {
        int v = G[u][i];
        if (!vis[v])
            dfs(v);
    }
    ans.push_back(u);
}

int main()
{
//    freopen("in.txt", "r", stdin);
    int n, m, a, b;
    while (~RII(n, m))
    {
        CLR(vis, false);
        ans.clear();
        FE(i, 1, n) G[i].clear();
        REP(i, m)
        {
            RII(a, b);
            G[b].push_back(a);
        }
        FE(i, 1, n)
        {
            if (!vis[i])
                dfs(i);
        }
        FED(i, ans.size() - 1, 0)
        {
            printf("%d ", ans[i]);
        }
        puts("");
    }
    return 0;
}
时间: 2024-10-09 08:36:43

Coder-Strike 2014 - Round 1__Giving Awards的相关文章

TCO 2014 Round 1C 概率DP

TCO round 1C的 250 和500 的题目都太脑残了,不说了. TCO round 1C 950 一个棋子,每次等概率的向左向右移动,然后走n步之后,期望cover的区域大小?求cover,肯定就是dp[l][r][n], 走了n步之后,左边cover了l,右边cover了r. 一开始DP没有搞清楚,这个要画一下图就更清楚了. 转移方程就是概率的传递方向. 1: double dp[505][505][2]; // l,r,n steps unsed; 2: class RedPain

Coder-Strike 2014 - Round 2

t题目链接:Coder-Strike 2014 - Round 2 A题:简单水题,注意能加入反复的数字.因此仅仅要推断是否能把Min和Max加入好.就能够了 B题:开一个sum计算每一个聊天总和,和一个s计算每一个人在每一个聊天总和,最后每一个人就用总和减掉自己发送的就可以 C题:最优策略为先把非特殊的答完,然后从最大的開始答 D题:dp,状态为dp[i][j][k],i表示当前长度,j表示前面数字的总和,k表示是否能组成,然后进行记忆化搜索 代码: A: #include <stdio.h>

Google Code Jam 2014 Round 2回顾和分析

回顾 比赛开始网络就一直在抽风,不知道宿舍网渣还是有人攻击服务器.刷了n遍n久刷出了题目.提交A小case的时候眼睁睁看着时间过去,却提交不上,这破网.最后A题B题还是解决了,C题扫了一眼,读都没读,就奔D题去了,因为我看到了熟悉的trie这个单词,加之看到小case只有9分,判断小case应该比较容易.前面因为网络浪费了很多时间,加之从未编过trie的程序,只能临时上网翻书去学,最后D小这个可以很容易暴力解的问题也没编完. 最终的rank是13xx,考虑到在这次GCJ之前从未接触过编程竞赛,而

[COCI 2013/2014 ROUND 4] guma

分析: 可以用欧拉函数来解决.对于要将一个小矩形等分成n份,那么需要在1/n,2/n,3/n...(n-1)/n处各切一刀,将这n-1个分数化成最简分数后,分母的集合即时n的所有因数(不包括1),且分母与分子互质,那么对于某个分母b来说,一共会有φ(b)个,则等分成n份要切 ∑φ(ai) (ai为n的因数,不包括1但包括n) 对于一个分母b如果之前被切过那么只需延长它即可,不用再切,这样我们就可以得到一个算法: 对于每个数找到它的所有因数,如果出现过就不管,没有出现过就把答案加上这个因数的欧拉函

[COCI 2013/2014 ROUND 5] ladice

分析:对于一个物品,只有两个抽屉A,B可以放,那么如果能够放下,那么一定是放在其中一个,设放在A中,那么以后可以且只能将其移动到B中,所以我们建一条有向边由A指向B,这样处理下去我们会发现对于每一条有向边一定是有物品的抽屉指向没有物品的抽屉,那么我们定义一个块为之间有边的点的集合,定义块的根为块中没有出边的点,那么一个块中只有根会是空的抽屉其他的一定是有物品的抽屉,那么每一个块就可以用一个并查集维护起来,每加一个物品(即加一条边)时,对于两个端点A,B,如果有A所在的并查集的根可以放那么就将A所

Google Code Jam 2014 Round 1B Problem B

二进制数位DP,涉及到数字的按位与操作. 查看官方解题报告 #include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> using namespace std; #define MAX_LEN 50 long long A, B, K; int a[MAX_LEN], b[MAX_LEN], k[MAX_LEN]; long long memoize[MAX_LEN]

[COCI 2013/2014 ROUND 6] hash

分析: 很容易想到时间复杂度为O(26n)的暴力枚举算法,但由于n<=10,很明显会超时,这时会有一个比较常用的方法:折半枚举. 分别枚举前半段和后半段,把满足条件的结合起来就是答案. 对于f[i]=((f[i-1]*33) xor letter[i]) mod 2m 前半段很好做,直接带入公式,定义g[i]为hash值为i的个数,进行记录 后半段可以这样做: 在此题的背景下,因为m>=6,且1<=letter[i]<=26,所以 (a xor b) mod 2m=(a mod 2

[COCI 2013/2014 ROUND 6] graskrizja

分析: 这个题可以用分治的方法解决 先将所有的点按x坐标排序,以最中间的那个点的x坐标为轴,两边所有的点在轴上的对应的点加上,然后分别以同样的方法处理左右两个区间的点,递归处理下去知道区间只有一个点 下面是代码: 1 #include<cstdio> 2 #include<algorithm> 3 #define maxn 50100 4 using namespace std; 5 6 class Point 7 { 8 public: 9 int x,y; 10 void ge

Coder-Strike 2014 - Round 1__E-mail Addresses

题目链接 题意: 给定一个字符串,判断合法串的个数.对于形如[email protected]的串,满足:str1包括数字.字母.下划线且由字母开头:str2由字母.数字组成:str3由字母组成:三个串均非空,且是连续的串 分析: 题目没什么难度,就是处理起来比较麻烦.可以记录一下所有@和.出现的位置,然后判断符合条件的三个串有几个,乘积即可 const int MAXN = 1100000; char ipt[MAXN]; LL alp[MAXN], number[MAXN], under[M