#88 C

來源:互聯網
上載者:User

problem link http://codeforces.com/contest/117/problem/C

This problem needs to find 3-length ring in a type of graph call tournament

One important precondition of this problem is that :

A tournament is a directed graph without self-loops in which every pair of vertexes is connected by exactly one directed edge. That is, for any two vertexes u and v (u ≠ v) exists either an edge going from u to v, or an edge from v to u

My solution gets Accepted, but runs more than 2 times slower than the fastest solution. 

First tall about my solution, it's simple, using DFS to find ring.

Remind that in DFS, if the search path reaches a vertex with color gray(means this vertex has been started DFS, but hasn't finished), then a ring occur, moreover, for every vertex in the search path, if the vertex v's deep level is bigger than that gray vertex, then v is inside this ring. )

For every vertex in the DFS process, keep tracing the minimun length ring that it is in, if found the minimun ring which length is 3, then answer is near, by this time, 2 of the 3 vertex is known( in the DFS process, current visited vertex and the next visited vertex are always known), so just need to find the 3th vertex vx that satisfy G[vx][v1] == 1 && G[v2][vx] == 1. 

#include <stdio.h>

#define MAX 5001

#define WHITE 0
#define GRAY 1
#define BLACK 2

int G[MAX][MAX] = { 0 };
int v_stack[MAX] = { 0 };
int e_stack[MAX] = { 0 };
int deep[MAX ] = { 0 };
int v_color[MAX] = { 0 };
int min_ring_dest[MAX] = { 0 };
int min_ring_len[MAX] = { 0 };
int N;
char line[MAX] = { 0 };
int r1, r2, r3;

void find_3th(int v1, int v2) {
r1 = v1;
r2 = v2;
int i, j;
for( i=1;i<=N;i++ ) {
if( 1 == G[v2][i] && 1 == G[i][v1] ) {
r3 = i;
break;
}
}
}

bool dfs(int v) {
int stack_cnt = 0, i, ring_len, e, d;
v_stack[stack_cnt] = v;
e_stack[stack_cnt++] = 1;
v_color[v] = GRAY;
while( 0 != stack_cnt ) {
e = e_stack[stack_cnt-1];
v = v_stack[stack_cnt-1];
for( i=e;i<=N;i++ ) {
if( 1 == G[v][i] ) {
if( WHITE == v_color[i] ) { // unvisited vertex, add to stack ( search path )
e_stack[stack_cnt-1] = i; // next time find arc start from i+1, but need to check i for ring length before.
v_stack[stack_cnt] = i;
e_stack[stack_cnt++] = 1;
v_color[i] = GRAY;
deep[i] = deep[v]+1;
break;
}
else if ( GRAY == v_color[i] ) { // ring.
ring_len = deep[v] + 1 - deep[i];
if( 0 == min_ring_len[v] || ring_len < min_ring_len[v] ) { // update
min_ring_len[v] = ring_len;
if( 0 == min_ring_len[i] ) // i doesn't know himself inside a ring.
min_ring_dest[v] = i;
else
min_ring_dest[v] = min_ring_dest[i];
}
if( 3 == ring_len ) {
find_3th(v, i);
return true;
}
}
else { // if ( BLACK == v_color[i] )
if( min_ring_len[i] > 0 ) { // i inside a ring.
d = min_ring_dest[i];
if( deep[d] <= deep[v] && GRAY == v_color[d] ) { // oh, the terminal vertex of i's ring is v's ancesstor or even v itself.
ring_len = min_ring_len[i] - ( deep[i] - ( deep[v] + 1 ) ); // reduce the i's ring len.
if( 0 == min_ring_len[v] || ring_len < min_ring_len[v] ) {
min_ring_len[v] = ring_len;
min_ring_dest[v] = d;
}

if( 3 == ring_len ) {
find_3th(v, i);
return true;
}
}
}
}
}
}
if( i == N + 1 ) { // v adds no arc to stack, means v need to be black
v_color[v] = BLACK;
stack_cnt--;
}
}

return false;
}


int main() {
scanf("%d", &N);
int i,j,k;
for( i=1;i<=N;i++ ) {
scanf("%s", line);
for( j=0;j<N;j++ ) {
if( '1' == line[j] ) {
G[i][j+1] = 1;
}
}
}

for( i=1;i<=N;i++ ) {
if( WHITE == v_color[i] ) {
if( true == dfs(i) ) {
printf("%d %d %d\n", r1, r2, r3);
return 0;
}
}
}

printf("-1\n");

return 0;
}

My solution needs to record too many information that isn't necessary for this problem.

Here's the fastest solution in codeforces, author: syboy.

syboy's solution is much efficient、grace and appropriate for this problem.

Base on the definition of tournament graph, for every vertex v in graph, the rest vertexes could be devided into exactly two sets-- vertexes emanate v (S1) and vertexes emanated from v (S2).

So for v, if any vertex v1 in S2 can reach any vertex v2 in S1, then a 3 length ring is form.

If there's no such (v1, v2), then recursively do the same division for the subgraph S1, S2 respectively,  until target ring is found.

Here is his code

//BE NAMASH


#include<iostream>
#include<stdio.h>
using namespace std;
const int MN=5100;
bool a[MN][MN];
short int A,B,C,l[MN],t[MN];
int n;
int find(int p,int q){
if(q-p<=2){
return 0;
}
int ef1=p+1,ef2=q-1;
int v=l[p];
t[p]=l[p];
for(int i=p+1;i<q;i++){
if(a[v][l[i]]){
t[ef2--]=l[i];
}else{
t[ef1++]=l[i];
}
}
for(int i=p+1;i<ef1;i++){
int v2=t[i];
for(int j=ef2+1;j<q;j++){
if(a[t[j]][v2]){
A=v;
B=t[j];
C=t[i];
return 1;
}
}
}
for(int i=p;i<q;i++){
l[i]=t[i];
}
if(find(p+1,ef1)||find(ef2+1,q)){
return 1;
}return 0;
}
char inp[50000000];
int main(){
// scanf("%d",&n);
cin>>n;
cin.read(inp,49999999);
int st=0;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
while(inp[st]!='0'&&inp[st]!='1'){
st++;
}
a[i][j]=inp[st]-'0';
st++;
}
l[i]=i;
}
if(find(0,n)){
cout<<A+1<<" "<<B+1<<" "<<C+1<<endl;
}else{
cout<<"-1"<<endl;
}return 0;
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.