hdu 5.2.6 3231 box relations

默……停了好久……終於良心發現了……

Box Relations

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 84 Accepted Submission(s): 35
 
Problem Description
There are n boxes C1, C2, ..., Cn in 3D space. The edges of the boxes are parallel to the x, y or z-axis. We provide some relations of the boxes, and your task is to construct a set of boxes satisfying all these relations.

There are four kinds of relations (1 <= i,j <= ni is different from j):
  • I i j: The intersection volume of Ci and Cj is positive.
  • X i j: The intersection volume is zero, and any point inside Ci has smaller x-coordinate than any point inside Cj.
  • Y i j: The intersection volume is zero, and any point inside Ci has smaller y-coordinate than any point inside Cj.
  • Z i j: The intersection volume is zero, and any point inside Ci has smaller z-coordinate than any point inside Cj.
.
 
Input
There will be at most 30 test cases. Each case begins with a line containing two integers n (1 <= n <= 1,000) and R (0 <= R <= 100,000), the number of boxes and the number of relations. Each of the following R lines describes a relation, written in the format above. The last test case is followed by n=R=0, which should not be processed.
 
Output

            For each test case, print the case number and either the word POSSIBLE or IMPOSSIBLE. If it\\\\\\\'s possible to construct the set of boxes, the i-th line of the following n lines contains six integers x1, y1, z1, x2, y2, z2, that means the i-th box is the set of points (x,y,z) satisfying x1 <= x <= x2, y1 <= y <= y2, z1 <= z <= z2. The absolute values of x1, y1, z1, x2, y2, z2 should not exceed 1,000,000.

Print a blank line after the output of each test case.
 
Sample Input
3 2
I 1 2
X 2 3
3 3
Z 1 2
Z 2 3
Z 3 1
1 0
0 0
 
Sample Output
Case 1: POSSIBLE
0 0 0 2 2 2
1 1 1 3 3 3
8 8 8 9 9 9

Case 2: IMPOSSIBLE

Case 3: POSSIBLE
0 0 0 1 1 1
 

這題顯然我是不會做的……(喂!好得意嘛!)看大家說要用拓撲排序……那……那就先看看拓撲是個啥吧……

對一個有向無環圖(Directed Acyclic Graph簡稱DAG)G進行拓撲排序,是將G中所有頂點排成一個線性序列,使得圖中任意一對頂點u和v,若<u,v> ∈E(G),則u在線性序列中出現在v之前。  --百度百科

so……不如……還是直接抄代碼好了………………sign

#include <iostream>
using namespace std;
#define N 2001
#define M 500000

int NE;
int n;
int head[4][N];
int q[4][N];
int degree[4][N];
int ans[4][N];

struct node
{
       int v,next;
       node(){};
       node(int a,int b)
       {
           next=a;v=b;
       }
}E[M];

void insert(int type,int u,int v)
{
     E[NE]=node(head[type][u],v);//add a new edge
     head[type][u]=NE++;
     degree[type][v]++;
}

bool topsort(int type)
{
     int front=1,top=0;
     for(int i=1;i<=2*n;i++)
     {
             if(degree[type][i]==0)
             {
                 q[type][top++]=i;
                 degree[type][i]--;
             }
     }
     while(front<top)
     {
         int u=q[type][front++];
         for(int i=head[type][u];i!=-1;i=E[i].next)
         {
                 int v=E[i].v;
                 degree[type][v]--;
                 if(degree[type][v]==0)
                 {
                     q[type][top++]=v;
                     degree[type][v]--;
                 }
         }
     }
     return top==2*n;
}

void solve()
{
     for(int i=1;i<=3;i++)
     {
             if(!topsort(i))
             {
                 cout<<"IMPOSSIBLE"<<endl;
                 return ;
             }
     }
     cout<<"POSSIBLE"<<endl;
     for(int i=1;i<=3;i++)
     {
         for(int j=0;j<2*n;j++)
         {
             ans[i][q[i][j]]=j;
         }
     }
     for(int i=1;i<=n;i++)
     {
             cout<<ans[1][i]<<" "<<ans[2][i]<<" "<<ans[3][i]<<endl;
             cout<<ans[1][i+n]<<" "<<ans[2][i+n]<<" "<<ans[3][i+n]<<endl;
     }
}

void init()
{
     NE=0;
     memset(degree,0,sizeof(degree));
     memset(head,-1,sizeof(head));
     for(int i=1;i<=n;i++)
         for(int j=1;j<=3;j++)
             insert(j,i,i+n);
}


int main()
{
    char ch[2];
    int a,b;
    int k=1;//record the number of case for print
    int m;
    while(cin>>n>>m,n||m)
    {
        init();
        while(m--)
        {
            cin>>ch>>a>>b;
            if(ch[0]=='I')
            {
                for(int i=1;i<=3;i++)
                {
                    insert(i,a,b+n);
                    insert(i,b,a+n);
                }
            }
            else
                 insert(ch[0]-'X'+1,a+n,b);
        }
        cout<<"Case "<<k++<<": ";
        solve();
        cout<<endl;
    }
}
                

居然超時了……情何以堪……重點是連超時的代碼我都看不懂………………


時間靜靜的過去了一個多月……終於繞了一圈回到了這道題(這也是我喜歡step的地方……必須面對自己慘淡的人生啊……)差點又碼一遍錯的代碼……這次……讓我好好理解一下吧至少……話說這次錯的代碼交上去是system error。。。那是個毛?!

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

#define N 2002
#define M 500000

struct node{
       int ed;
       node *next;
}e[M],*head[4][N];

int pos;
int n;
int q[4][N];
int in[4][N];//number of n's in-degree
int ans[4][N];

void insert(int type,int a,int b);

void init()
{
     pos=0;
     memset(head,0,sizeof(head));
     memset(in,0,sizeof(in));
     for(int i=1;i<=n;i++)
         for(int j=1;j<=3;j++)
             insert(j,i,i+n);//every cube has its original requirement
}

void insert(int type,int a,int b)
{
     e[pos].ed=b;//the end point of the edge
     e[pos].next=head[type][a];//if have several end point
     head[type][a]=&e[pos++];//head point to now edge 
     in[type][b]++;//the end point's in-degree ++
}

bool topsort(int type)
{
    int front,top;
    front=top=0;
    for(int i=1;i<=2*n;i++)
    {
        if(!in[type][i])//no in-degree
        {
            q[type][top++]=i;//enqueue
        }
    }
    while(front<top)
    {
        int u=q[type][front++];
        for(node *p=head[type][u];p;p=p->next)//tear all the edge of the start point
        {
            in[type][p->ed]--;//tear the edge, the end point's in-degree minus
            if(!in[type][p->ed])//check if the end point has no in-degree
            {
                q[type][top++]=p->ed;//enqueue
            }
        }
    }
    return top==2*n;//all point enqueued
}


void solve()
{
    for(int i=1;i<=3;i++)
    {
        bool flag=topsort(i);
        if(!flag)
        {
            puts("IMPOSSIBLE");
            return;
        }
    }
    puts("POSSIBLE");
    for(int i=0;i<2*n;i++)
        for(int j=1;j<=3;j++)
            ans[j][q[j][i]]=i;
    for(int i=1;i<=n;i++)
        printf("%d %d %d %d %d %d\n", ans[1][i], ans[2][i], ans[3][i],ans[1][i + n], ans[2][i + n], ans[3][i + n]);
}




int main(void){  
    char ch[2];  
    int a,b;  
    int cas=1;
    int r;  
    while(cin>>n>>r,n||r){  
        init();  
        while(r--){  
            //cin>>ch>>a>>b; //if use cin...timelimit exceeded....no...
            scanf("%s %d %d", &ch, &a, &b);
            if(ch[0]=='I'){  
                for(int i=1;i<=3;i++){  
                    insert(i,a,b+n);  
                    insert(i,b,a+n);  
                }  
            }  
            else  
                insert(ch[0]-'X'+1,a+n,b);//this is great  
        }  
        printf("Case %d: ",cas++);  
        solve();  
        printf("\n");  
    }  
    return 0;
}  

算是差不多知道是怎麼回事了……但讓我自己寫果然還是有些難吧……

用的是一個三維的拓撲排序,其實就是建一個3維數組分別加入邊,排序和輸出而已……

可以簡化成一維的先理解下。

就是每個線段有兩個端點,a+n大於a,即a端指向a+n端(共n條線段),即a->a+n。兩個線段(a,b)間有兩種情況。1相交,則a+n大於b,b+n大於a。2.x a b,即b大於a+n。

然後把所有的邊放在一起拓撲排序~具體如下:


這樣得到一個拓樸序列 v 1 , v 6 , v 4 , v 3 , v 2 , v 5 。 

是的請叫我粘貼黨。

代碼實現也差不多,找無入度點,找它指向的所有後續點,刪邊減點。這裏的node中用的是next指針,指向下一個由同一起始點指向的終點。如對於1有三個終點234,則1指向的終點可能是4,而4會指向3,3會指向2。……總覺得好麻煩。

這個程序除了還有些使用困難的拓撲排序外,還有兩個小點。一是cin真的要慎用。140ms到超時,就是這麼可怕。二是自己腦殘了居然把i和j設成全局變量!!腦子無疑是被槍打了。害我調半天混蛋- -

終於over了。5.3進軍!頑張る!!



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章