C語言實現 藍橋杯 算法訓練 Two k-Convex Polygons

👇聯繫我

試題 算法訓練 Two k-Convex Polygons

                                                                                  藍橋杯試題解答彙總鏈接

資源限制

       時間限制:500ms 內存限制:256.0MB


問題描述

       給定n個棍子的長度和整數k,求能否在其中選出2k個棍子拼成兩個凸多邊形。使得兩個凸多邊形都恰好有k跟棍子組成,且任意相鄰的邊都不共線。


輸入格式

       第一行包括兩個正整數n,k,表示棍子總數和多邊形邊數。
  第二行包括n個正整數,表示每根棍子的長度。


輸出格式

       第一行輸出一個單詞Yes或者No表示是否能選出滿足要求的2k個棍子。
  如果第一行輸出的是Yes,則第二行要輸出方案。輸入的棍子從1開始按照輸入順序編號,你需要輸出2k個空格隔開的正整數,前k個表示組成第一個凸多邊形的棍子的編號,後k個表示組成第二個凸多邊形棍子的編號。
  如果有多種方案,輸出任意一種即可。


樣例輸入

Input 1:
6 3
1 1 1 2 2 2

Input 2:
6 3
1 2 3 100 200 300

樣例輸出

Output 1:
Yes
1 2 3 4 5 6

Output 2:
No

數據規模與約定

2k ≤ n ≤ 1000
3 ≤ k ≤ 10
1 ≤ length of each stick ≤ 10^9

試題解析

①:k根棍子能組成k凸邊形的條件:任何邊小於其他所有邊的和(即最大邊小於其他所有邊的和
證:設sum爲k-1條邊之和,a爲最大邊,x爲任意的其他邊;若a爲和sum的組成之一,又a>x,所以只要sum>a即可

②:又只要找到一種組合情況即可,故我們先對樣本數據從小到大排列此時可得若存在不連續組合那麼它一定存在連續的組合以下拿k=3舉例
證:設x∈[1,n],k=3
若ax+ax+2>ax+4
又ax<ax+1對任意x∈[1,n-1]成立
則有ax+3+ax+2>ax+4(ax+2、ax+3、ax+4爲連續)
所以我們只需要找到連續的組合情況即可,但我們每次要找的是2k條邊,所以選取的2k條連續的邊可能出現兩種存在兩種組合的情況:
(1)2k條邊中前k條邊一組後面k條邊一組滿足題意;(枚舉;對應代碼66行)
(2)2k條邊中每組的k條邊不是連續的;(暴搜;對應代碼73行)


代碼

#include<stdio.h>
int n,k,v[1000],flage = 0;// n、k與題意一致;v數組用來暴搜標記一組的k根棒子;flag用來標記是否存在滿足條件的2k根棍子的組合 
void BubbleSort(int a[][2],int n){// 冒泡排序算法用於對給出樣本的進行從小到大的排序 
	int f = 1,i,j,t;
	for(i = 0;i < n&&f == 1;i++){
		f = 0;
		for(j = n-1;j > i;j--){
			if(a[j-1][0] > a[j][0]){
				f = 1;
				t = a[j-1][0];
				a[j-1][0] = a[j][0];
				a[j][0] = t;
				t = a[j-1][1];
				a[j-1][1] = a[j][1];
				a[j][1] = t;
			}
		}
	}
}
int sum(int a[][2],int low,int high){// 求和函數用於求下標爲low-high的樣本的和 
	int i,m = 0;
	for(i = low;i <= high;i++){
		m += a[i][0];
	}
	return m;
}
void dfs(int a[][2],int low,int high,int sum1,int sum2,int count1,int count2,int num1,int num2){// 暴搜求不連續的組合 
    // low、high分別爲遞歸起點和終點;sum1、sum2分別統計各組數據的長度總和;
	// c1、c2分別統計各小組的已入選的數據個數;mx1、mx2分別標記每組當前數據中最後一個數據的值 
	int i;
	if(low == high+1&&flage == 0){//遞歸至兩組都選滿k個時即low=high+1且目前不存在這樣的情況進入 
    	if(sum1-num1 > num1&&sum2-num2 > num2){
    		printf("Yes\n");
    		flage = 1;// 滿足條件則標記flage爲1表示存在這樣的情況 
    		for(i = high-2*k+1;i <= high;i++){
    			if(v[i] == 0){// 先輸出第一組 
    				printf("%d ",a[i][1]);
    			}
    		}
    		for(i = high-2*k+1;i <= high;i++){
    			if(v[i] == 1){// 在輸出第二組 
    				printf("%d ",a[i][1]);
    			}
    		}
    	}
    }
    if(count1 != k){// 先對第一組進行遞歸滿k個後在遞歸第二組 
    	v[low] = 0;// 第一組成員標記爲0 
    	dfs(a,low + 1,high,sum1 + a[low][0],sum2,count1 + 1,count2,a[low][0],num2);
    }
    if(count2 != k){// 第一組選好第二組遞歸開始 
    	v[low] = 1;// 第二組成員標記爲1 
    	dfs(a,low + 1,high,sum1,sum2 + a[low][0],count1,count2 + 1,num1,a[low][0]);
    }
}
int main(){
	scanf("%d%d",&n,&k);
	int i,j,a[n][2];
	for(i = 0;i < n;i++){
		scanf("%d",&a[i][0]);
		a[i][1] = i+1;// 給每根棍子標號 
	}
	BubbleSort(a,n);// 從小到大排序 
	for(i = 0;i <= n-2*k;i++){
		// 組合爲連續的情況 
		if(sum(a,i,i+k-2) > a[i+k-1][0]&&sum(a,i+k,i+2*k-2) > a[i+2*k-1][0]){ 
			printf("Yes\n");
			for(j = i;j < i+2*k;j++){
				printf("%d ",a[j][1]);
			}
			return 0;
		}// 組合爲不連續的情況 
		else if(sum(a,i+k,i+2*k-2) > a[i+2*k-1][0]){// 2k個數據中第二、三大的數據的和大於最大的數纔可能存在兩組否則最多是一個組合
			dfs(a,i,i+2*k-1,0,0,0,0,0,0);// 暴搜 
			if(flage){// 有一種情況滿足直接退出程序 
				return 0;
			}
		}
	}
	printf("No");// 沒有滿足的輸出No 
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章