hdu - 4324 - Triangle LOVE - 深搜

2000個點的有向圖,保證任意兩點間僅有一條有向邊,問是否存在一個三元環。

http://acm.hdu.edu.cn/showproblem.php?pid=4324

解法一:

     

如果把任意有公共頂點的兩邊構成的圖形看做一個角,可將角分爲是b的和不是b的(用a類表示),把任意三條邊看做一個三角形,可將三角形分爲x、y兩種。對於每個頂點入度爲in出度爲out則共有in*out種b種角,由於是競賽圖,因此有C(n,2)-in*out種a種角,根據3x+y=b,2y=a,因此x=(b-a/2)/3,即可求出三元環的個數。

解法二:

   歸結爲1個條件,任何兩人都有邊,要麼出要麼入。
對於有向三元環,我們知道找到:A->B->C->A ,B->C->A->B ,C->A->B->C 是一樣的,這給0(n^2)的算法提供了基礎。
對於每次枚舉i,我們在(0~i-1)的範圍看下有多少個i指向的點(剩下的就是指向i的點),同時算下i指向的點的出度和。就可以知道這些 i指向的點 指向 指向i的點(剩下的點)的數目,如果
              num * (num - 1) / 2 < sumout

 那麼就是被指向的點又指回去了,這樣就形成了3元環。

否則,剩下的就是更新下出度即可,繼續執行下一個節點。

解法三:

     結論:對於一個競賽圖,若存在n元環,一定存在一個n-1元環或者三元環,此題可以一遍拓撲排序判環求解即只需要找到一個環,就必定存在三元環。證明如下: 假設存在一個n元環,因爲a->b有邊,b->a必定沒邊,反之也成立 所以假設有環上三個相鄰的點a-> b-> c,那麼如果c->a間有邊,就已經形成了一個三元環,如果c->a沒邊,那麼a->c肯定有邊,這樣就形成了一個n-1元環。。。。 所以只需證明n爲4時一定有三元環即可,顯然成立。

解法四:

   增量算法,充分利用“任意兩點間僅有一條有向邊”的性質。
假設前面已經加入了N個點,現在來了第N+1個點。
那麼一定能將N個點分成left和right兩部分,使得N+1號點到left有邊,right到N+1號點右邊(因爲任意兩點間都有邊),那麼,如果left的任意一個點l到right任意一個點r有邊的話,那麼就有答案N+1->l->r->N+1這樣一個長度爲3的環。
那麼每次加入N+1號點後,用O(N)的複雜度求出左邊的數量leftnum,右邊的數量rightnum,left的出度和leftout,left的入度和leftin。
如果left沒有一條到right的邊,則一定滿足:
leftin = leftout + leftnum * rightnum(left和right任意兩點右邊,如果沒有左到右的,那麼leftnum*rightnum條邊都是右到左的)
那麼,如果leftin != leftout + leftnum * rightnum,則暴力枚舉左點,右點即可得到答案。
總體複雜度O(n^2)

解法五:

     直接深搜。

1:

int main(){
    scanf("%d",&T);
    for(int ca = 1; ca <= T; ca ++){
        scanf("%d",&n);
        memset(in, 0 , sizeof(in));
        memset(out, 0, sizeof(out));
        for(int i = 1; i <= n; i ++){
            scanf("%s",tmp + 1);
            for(int j = 1; j <= n; j ++){
                if(tmp[j] == '1'){
                    in[j] ++;
                    out[i] ++;
                }
            }
        }
        long long b, a, ans, all ;
        b = all = 0;
        for(int i = 1; i <= n; i ++){
            b += in[i] * out[i];
            all += (n - 1) * (n - 2) / 2;
        }
//        all += ( (n - 1) / 2 * (n - 2) )* n; 這麼寫就錯了,加在裏面就對,無語了。
//        printf("all af = %d\n", all);
         a = all - b;
         ans = ( b - a / 2 ) / 3;

//        printf("%dkaka\n", ans);

        printf("Case #%d: ",ca);
        if(ans) printf("Yes\n");
        else puts("No");
    }
    return 0;
}
2:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

const int maxn = 2012;
char s[maxn][maxn];
int InDegree[maxn];

int main(){
    int T;
    scanf("%d", &T);
    for(int t=1; t<=T; t++){

       int n;
       scanf("%d ", &n);
       for(int i=0; i<n; i++)
           gets(s[i]);
       for(int i=0; i<n; i++){
           InDegree[i] = 0;
           for(int j=0; j<n; j++){
              if(s[i][j] == '0' && i!=j)
                  InDegree[i]++;
           }
       }
       printf("Case #%d: ", t);
       for(int i=0; i<n; i++){
           int sum = 0, x = 0;
           for(int j=0; j<n; j++)
              if(s[j][i] == '1'){
                  sum += InDegree[j];//分兩組,記錄喜歡自己那組的入度和
                  x++;
              }
              //x爲指向i的有幾個, sum爲指向i的那幾個的入度和
           if(sum > x*(x-1)/2){
              printf("Yes\n");
              goto RL;
           }
       }
       printf("No\n");
       RL:continue;
    }
    return 0;
}


4:

#include <cstdio>
#include <cstring>
#define maxn 2010
using namespace std;
int T,n,edgenum, head[maxn * maxn];
char tmp[maxn];
bool vis[maxn], chu[maxn];
inline void initEdge(){
    memset(head, -1, sizeof(head));
    edgenum = 0;
}
struct Edge{
    int v, nxt;
}edge[maxn * maxn];
void addEdge(int u, int v){
    edge[edgenum].v = v;
    edge[edgenum].nxt = head[u];
    head[u] = edgenum ++;
}
bool record[maxn][maxn];
bool dfs(int u, int depth){
    if(vis[u]){
        if(depth > 2 && record[depth - 3][u])
            return true;
        return false;
    }else{
        vis[u] = true;
        record[depth][u] = true;
        for(int i = head[u]; i != -1; i = edge[i].nxt){
            if(dfs(edge[i].v, depth + 1))
                return true;
        }
    }
    return false;
}

int main(){
    scanf("%d",&T);
    for(int ca = 1; ca <= T; ca ++){
        scanf("%d",&n);
        initEdge();
        memset(chu, false, sizeof(chu));
        for(int i = 1; i <= n; i ++){
            scanf("%s",tmp + 1);
            for(int j = 1; j <= n; j ++){
                if(tmp[j] == '1'){
                    addEdge(i,j);
                    chu[i] = true;
                }
            }
        }
        memset(vis, false, sizeof(vis));
        memset(record, false, sizeof(record));
        bool flag = false;
        for(int i = 1; i <= n && !flag; i ++){
            if(!vis[i]&&chu[i]){
                flag = dfs(i, 0);
            }
        }
        printf("Case #%d: ",ca);
        if(flag) printf("Yes\n");
        else puts("No");
    }
    return 0;
}


發佈了177 篇原創文章 · 獲贊 2 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章