1. 程式人生 > >計蒜客 回收元件 拓撲排序(Java版)

計蒜客 回收元件 拓撲排序(Java版)

題目大意:將各個元件按照某個次序向y軸負半軸移動,直到所有元件全部移出工作區,我的想法是如果a元件的左端點橫座標在b元件兩個端點的橫座標中間時,判斷a元件左端點的縱座標ya與a元件左端點橫座標在b元件上的縱座標位置yb,如果ya大於yb,說明要先移動b元件,所以我們可以建圖點b指向a,a點的入度增加,n^2遍歷所有的元件之後可以得到一個圖,然後進行拓撲排序輸出即可。 ac程式碼:

import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main {
	static class edge {
		int x1,y1,x2,y2;
		edge(int a,int b,int c,int d){
			x1=a;
			y1=b;
			x2=c;
			y2=d;
		}		
	}
	static class bian{//用來存邊的鄰接表
		int v,next;
		bian(int v,int next){
			this.v=v;
			this.next=next;
		}
	}
	static int p[]=new int[6005];
	static bian b[]=new bian[5000000];//剛開始開200萬發現不夠
	static int eid=0;
	static void insert(int u,int v){
		b[eid]=new bian(v,p[u]);
		p[u]=eid++;
	}
	static edge e[]=new edge[6005];
	static int rudu[]=new int[6005];//儲存元件的入度
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		int n=sc.nextInt();
		Arrays.fill(p, -1);
		for(int i=1;i<=n;i++){
			int a=sc.nextInt();
			int b=sc.nextInt();
			int c=sc.nextInt();
			int d=sc.nextInt();
			if(a>c){
				int temp=a;
				a=c;
				c=temp;
				temp=b;
				b=d;
				d=temp;
			}
			e[i]=new edge(a,b,c,d);
		}
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				if(i!=j&&e[i].x1>=e[j].x1&&e[i].x1<=e[j].x2){
					double y;
					if(e[j].x1==e[j].x2)
						y=(e[j].y1+e[j].y2)/2.0;
					else
						y=1.0*(e[i].x1-e[j].x1)*(e[j].y2-e[j].y1)/(e[j].x2-e[j].x1)+e[j].y1;
					if(y>e[i].y1){  //比較兩個y的大小來判斷優先度
						rudu[j]++;
						insert(i,j);
					}else{
						rudu[i]++;
						insert(j,i);
					}
				}
			}
		}
		Queue<Integer> q=new LinkedList<Integer>();
		for(int i=1;i<=n;i++)  //拓撲排序,初始入度為0的點入佇列
			if(rudu[i]==0)
				q.add(i);
		while(!q.isEmpty()){
			int u=q.poll();
			for(int i=p[u];i!=-1;i=b[i].next){
				int v=b[i].v;
				if(--rudu[v]==0)
					q.add(v);
			}
			if(!q.isEmpty())
				System.out.print(u+" ");
			else
				System.out.println(u);
		}
		sc.close();
	}
}