2009-04-29 19:10:58來源不明

一堆線段

作法:利用集合的概念
想法:
1.設最大邊 然後去搜尋
2.搜尋原則:

    1. 最大邊與第二大邊的差 若可以被其他邊所超過 也就是稱得起來三角形 那麼剩餘的邊也可以藉由這個邊 建出組合
    2. 若不行 則利用遞迴將這個差值 拿不行撐起來的邊去試...
    3. 詳細情形請看以下作法

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;  
}

 

上一篇:質數合

下一篇:一堆石頭