1 条题解

  • 0
    @ 2025-5-6 21:42:54

    【题意】

    有N 个不同重量的球,重量为1~N 个单位。

    对球从1到N 进行标记,使得: ①没有两个球具有相同的标签;②标签满足几个约束,例如“标签为a 的球比标签为b 的球轻”。

    【输入输出】

    输入:

    第1行包含测试用例的数量。每个测试用例的第1行都包含两个整数N (1≤N ≤200)和M (0≤M ≤40000),分别表示球的数量和约束的数量。后面的M 行,每行都包含两个整数a 和b ,表示标签为a 的球比标签为b 的球轻(1≤a ,b ≤N )。

    在每个测试用例前都有一个空行。

    输出:

    对于每个测试用例,都单行输出标签1~N 的球的重量。如果存在多种解决方案,则输出标签为1的球的最小重量,然后输出标签为2的球的最小重量,以此类推……如果不存在解,则输出-1。

    【思路分析】

    这道题不是输出小球的标签,而是按照标签输出小球的重量,而且标签小的球的重量尽可能小。

    举个栗子:

    输入以下数据,

    5 4 //节点数 5 1 //标签为5 的球比标签为1 的球轻 4 2 1 3 2 3 1 2 3 4 5

    根据重量关系,节点3 是最重的。因此令重量weight[3]=5;节点1和节点2比节点3轻,因为每个球的重量都不同,按照标签小的球重量小的原则,先给标签大的球分配重量,先处理节点2,因此weight[2]=4;节点4比节点2轻,weight[4]=3;节点1比节点3轻,weight[1]=2;节点5比节点1轻,weight[5]=1。按照标签1~5输出其重量:2 4 5 3 1。

    例如,输入以下数据

    10 5 //节点数、边数 4 1 //标签为4 的球比标签为1 的球轻 8 1 7 8 4 1 2 8 1 2 3 4 5 6

    按照标签小的球重量小的原则,先给标签大的球分配重量:weight[10]=10;weight[9]=9;weight[6]=8;weight[5]=7;weight[3]=6;weight[1]=5。节点8和节点4比节点1轻,按照标签小的球重量小的原则,先给标签大的球分配重量,先处理节点8,因此weight[8]=4;节点7和节点2比节点8轻,先处理节点7,weight[7]=3;现在只剩下节点4和节点2,weight[4]=2;weight[2]=1。

    按照标签1~10输出其重量:5 1 6 2 7 8 3 4 9 10。

    这道题有重复边,需要去重,否则会有环,最后输出-1

    【算法设计】

    方法1:建立正向图。i =n …1,j =n …1,检查第1个出度为0的点t ,分配重量w [t ]=i ,将弧尾节点的出度减1,继续下一个循环。若没有出度为0的节点,则说明有环,退出。 方法2:建立原图的逆向图。i =n …1,j =n …1,检查第1个入度为0的节点t ,分配重量w [t ]=i ,将其邻接点的入度减1,继续下一个循环。若没有入度为0的节点,则说明有环,退出。

    #include<iostream>
    #include<cstring>
    #include<stack>
    
    using namespace std;
    const int maxn = 210;
    int map[maxn][maxn], in[maxn] , w[maxn];
    
    int n , m , T, u ,v;
    bool flag;
    
    void TopoSort(){ //拓扑排序 
    	
    	flag = 0;
    	for(int i = n ; i > 0 ; i --){
    		
    		int t = -1;
    		for(int j = n ; j > 0 ; j--){
    			
    			if(!in[j]){
    				
    				t = j;
    				break;
    			}
    		}
    		if(t == -1){ //有环 
    			
    			flag = 1;
    			return;
    		}
    		
    		in[t] = -1;
    		w[t] = i;
    		for(int j = 1 ; j <= n ; j ++){
    			
    			if(map[t][j]){
    				in[j] --;
    			}
    		}
    	}
    } 
    
    int main(){
    	
    	cin >> T;
    	
    	while(T--){
    		
    		memset(map , 0 ,sizeof(map));
    		memset(in , 0 , sizeof(in));
    		
    		cin >> n >> m;
    		for(int i = 1; i <= m ; i++){
    			
    			cin >> u >> v;
    			if(!map[v][u]){ //建立逆向图,检查重复边 
    				
    				map[v][u] = 1;
    				in[u] ++;
    			}
    		}
    		TopoSort();
    		if(flag){
    			cout << -1 << endl;
    			continue;
    		}
    		
    		for(int i = 1; i < n ; i++){
    			
    			cout << w[i] << " ";
    		}
    		cout << w[n] << endl;
    	}
    	return 0;
    }
    • 1

    信息

    ID
    2688
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者