HDU 5961传递 思维 + bitset

传送门:HDU 5961

题意:中文题

思路:这题如果按hdu上的6s时限的话就有很多做法了,从每个点开始bfs判断是否有长度大于等于2的最短路径,或者dfs判断给出的图中是否有三元环等等,但是据说现场赛是1500ms时限,那这些做法就都不行了。

能在现场赛实现下通过的一个方法是用bitset将每个点的出边保存下来,然后枚举每一条边,判断该边的两个端点的出边是否都为下图的情况

HDU 5961传递 思维 + bitset_第1张图片

即判断是否只要有BC边就有AC边,具体做法就是用bitset[B] & bitset[A]看看结果是否等于bitset[B]

这样复杂度就是O(n ^ 2 / 64)了。

尽管我已经尽我所能优化了代码,但是还是很卡时间上限,多交几次才能有一次卡进1500ms内。。

代码:

#include
using namespace std;
const int MAXN = 2017;
const int MAXM = MAXN * MAXN;
struct node{
    int v, next;
    node(int _v = 0, int _next = 0) : v(_v), next(_next) {}
}mp[MAXM];
int pre[MAXN], cnt, n;
bitset g[MAXN];
void init()
{
    for(int i = 0; i < n; i++) g[i].reset();
    memset(pre, -1, sizeof(int) * n);
    cnt = 0;
}
void addedge(int u, int v)
{
    mp[cnt] = node(v, pre[u]); pre[u] = cnt++;
}
char s[MAXN][MAXN];
bool check(char ch)
{
    init();
    for(int i = 0; i < n; i++)
        for(int j = 0; j < n; j++)
            if(s[i][j] == ch)
            addedge(i, j), g[i][j] = 1;
    for(int i = 0; i < n; i++)
        for(int j = pre[i]; ~j; j = mp[j].next)
        if((g[i] & g[mp[j].v]) != g[mp[j].v])
        return 0;
    return 1;
}
int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        for(int i = 0; i < n; i++)
            scanf("%s", s[i]);
        if(!check('P') || !check('Q')) puts("N");
        else puts("T");
    }
}


你可能感兴趣的:(hdu,各种思维题,STL)