一堆線段
作法:利用集合的概念
想法:
1.設最大邊 然後去搜尋
2.搜尋原則:
- 最大邊與第二大邊的差 若可以被其他邊所超過 也就是稱得起來三角形 那麼剩餘的邊也可以藉由這個邊 建出組合
- 若不行 則利用遞迴將這個差值 拿不行撐起來的邊去試...
- 詳細情形請看以下作法
teching所提供的解法與解釋如下
/*************************************************************/
我的方法是採用部分集合的方式,其實就是巴斯卡三角形,但是算過的不再重複計算就是了.
#include <stdio.h>
int cnt=0; //多邊形條件:最大邊必須小於其他邊的和
int num[101]; //從第二大邊開始向下加,直到和大於最大邊為止
//剩餘 n 個邊有 2^n 種組合,都可以和之前的邊組合多邊形
void calc (int s, int i) { //s (side)--最大邊長扣除其他較大邊長所剩長度
for (; i>=0; i--)
if (num[i] > s)
cnt += 1 << i; //加 2 的 i 次方
else
break;
for (; i>0; i--)
calc (s-num[i], i-1); //減掉邊長後繼續試
}
int main()
{
char c;
int i=0,j=0,m=0,n=0,cnt1=0,temp=0;
for (i=0;i<101;i++) num[i]=0;
while (1){
cnt1=0;
while(scanf("%d%c", &n, &c)==2){
if (n == 0) return 0;
num[cnt1] = n;
cnt1=cnt1+1;
if(c!='\n') continue;
else break;
}
for (i=0;i<cnt1-1;i++){
for (j=i+1;j<cnt1;j++){
if (num[i] > num[j]){
temp = num[i];
num[i] = num[j];
num[j] = temp;
}
}
}
cnt = 0;
for (i=2; i<cnt1; i++) //嘗試以各個線段作為最大邊
for (j=i-1; j; j--){ //嘗試以各個比 side(i) 小的線段為第二大邊
calc (num[i]-num[j], j-1);
}
printf ("%d\n", cnt);
}
return 0;
}
/********我的修改(習慣我的作法 請看這邊)
************************/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int temp[101]={0},ans=0;
void calc (int s, int i)
{ /*s (side)--最大邊長扣除其他較大邊長所剩長度*/
for (; i>=0; i--)
if (temp[i] > s)
ans += 1 << i; /*加 2 的 i 次方*/
else
break;
for (; i>0; i--)
calc (s-temp[i], i-1); /*減掉邊長後繼續試*/
}
main()
{
char x[10000];
while(gets(x))
{
if(x[0]=='0'&&strlen(x)==1) break;
int n=0;
int m,a,b,c,mm=strlen(x);
for(a=0;a<100;a++) temp[a]=0;
for(a=0;a<mm;a++)
{
if(x[a]<=57&&x[a]>=48)
temp[n]=temp[n]*10+x[a]-48;
else n++;
}
n++;
for(a=0;a<n;a++)/*排序好 小→大*/
{
c=a;
for(b=a+1;b<n;b++)
if(temp[b]<temp[c]) c=b;
if(c!=a)
{
int temp1;
temp1=temp[c];
temp[c]=temp[a];
temp[a]=temp1;
}
}
ans=0;
for(a=2;a<n;a++)
for(b=a-1;b>0;b--)
calc(temp[a]-temp[b],b-1);
printf("%d\n",ans);
}
return 0;
}
/************************************************************/
作法II:窮舉 任一邊接大於其他邊的總和
遞迴生成組合((比較快
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int way[1001]={0};
int n,a,b,c;
int num[201]={0},ans;
void make (int now,int a,int n,int m,int sum)
{
int b=a,c;
if(now==m+1&&now>=4)
{
/* for(c=1;c<=now-1;c++)
printf("%d ",num[way[c]]);
printf(" %d\n",sum); */
if(num[way[1]]<sum-num[way[1]]) ans++;
return;
}
if(now>=4)
{
/* for(c=1;c<=now-1;c++)
printf("%d ",num[way[c]]);
printf(" %d\n",sum); */
if(num[way[1]]<sum-num[way[1]]) ans++;
}
for(b=a;b<=n;b++)
{
way[now]=b;
make(now+1,b+1,n,m,sum+num[way[now]]);
}
}
main()
{
char in[500]={0};
while(gets(in))
{
if(strlen(in)==1&&in[0]=='0') break;
ans=0;n=1;
int mm=strlen(in),temp=0;
for(a=0;a<mm;a++)
if(in[a]<=57&&in[a]>=48)
temp=temp*10+in[a]-48;
else {num[n]=temp;n++;temp=0;}
num[n]=temp;
for(a=1;a<=n;a++)
{
c=a;
for(b=a+1;b<=n;b++)
if(num[b]>num[c]) c=b;
int temp;
temp=num[c];
num[c]=num[a];
num[a]=temp;
}
make(1,1,n,n,0);
printf("%d\n",ans);
}
return 0;
}