2015年9月30日 星期三

[UVA] 12019 - Doom's Day Algorithm

題意:
輸入一個日期,
輸出在2011年該日期是星期幾

--------------------------------------------------

/* 20150930
 * hanting
 * UVa 12019 - Doom's Day Algorithm
 * C++
 */
#include <iostream>
using namespace std;
#define YearID(x) ((x-2000)/4+(x-2000))
int main()
{
    int caseN;
    cin>>caseN;
    string Day[]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
    int MonID[]={0,6,2,2,5,0,3,5,1,4,6,2,4};
    while(caseN--)
    {
        int mon,date;
        cin>>mon>>date;
        int ans=(YearID(2011)+ MonID[mon] + date )%7;
        cout<<Day[ans]<<endl;
    }

    return 0;
}

[UVA] 11332 - Summing Digits

題意:
f(n)=
n<10 , n
n>=10 ,f(n每個位數相加)
--------------------------------------------------

我的作法:
照著函數打囉!

--------------------------------------------------

/* 20150930
 * hanting
 * UVa 11332 - Summing Digits
 * C++
 */
#include <iostream>
using namespace std;
int f(int n)
{
    int t=0;
    while(n)
    {
        t+=n%10;
        n/=10;
    }
    return t<10 ? t:f(t);
}
int main()
{
    int num;
    while(cin>>num and num)
    {
        cout<<f(num)<<endl;
    }

    return 0;
}

[UVA] 10929 - You can say 11

題意:
給一個數字,判斷是不是11的倍數!

--------------------------------------------------

我的作法:
注意!因為位數很大(1000位數),要用string輸入,再將每個字元轉成數字。
11有兩個1,建立兩個盒子!分別代表個位數和十位數~
將輸入的數字從個位數開始交叉放進盒子,
如果盒子值是11的倍數,
那輸入的數字也是11的倍數!
例如:
12345678
8放個位數的盒子,
7放十位數的盒子,
6放個位數的盒子,
5放十位數的盒子,
4放個位數的盒子,
3放十位數的盒子,
2放個位數的盒子,
1放十位數的盒子,

所以十位數的盒子有1 + 3 + 5 + 7 = 16 ,盒子的值 = 16 * 10 = 16
個位數的盒子有 2 + 4 + 6 + 8 = 20,盒子的值 = 20
16+20=36,
36不是11的倍數!所以12345678也不是11的倍數!

再舉個例子:
5321459
9放個位數的盒子,
5放十位數的盒子,
4放個位數的盒子,
1放十位數的盒子,
2放個位數的盒子,
3放十位數的盒子,
5放個位數的盒子,

所以十位數的盒子有 3 + 1 + 5 = 9,盒子的值 = 9 * 10 = 90
個位數的盒子有 5 + 2 + 4 + 9  = 20,盒子的值 = 20
90+20=110,
110是11的倍數!所以5321459也是11的倍數!
神奇寶貝

--------------------------------------------------

/* 20150930
 * hanting
 * UVa 10929 - You can say 11
 * C++
 */
#include <iostream>
using namespace std;
#define INT(x) x-48
int main()
{
    string num;
    while(cin>>num and num!="0")
    {
        int box[2]={0};
        for(int i=0;i<num.size();i++)
        {
            if(i&1) box[1]+=INT(num[i]);
            else box[0]+=INT(num[i]);
        }
        int boxValue=box[0]+box[1]*10;
        if(boxValue%11==0)
        {
            cout<<num<<" is a multiple of 11."<<endl;
        }
        else
        {
            cout<<num<<" is not a multiple of 11."<<endl;
        }
    }

    return 0;
}

2015年9月29日 星期二

[UVA] 10371 Time Zones

題意:
給時間, 字串A, 字串B
字串A B可以根據他給的表轉成數字A和數字B
輸出時間 + (數字B - 數字A)
--------------------------------------------------

我的作法:
可以把時間變成24小時制
12:00 a.m. 變成 0:00
1:00 p.m. 變成 13:00
在做時間相加或相減可以先把時:分都先換成
例如:
1306分 + 5.5
136分 = 13*60+6 = 0786
5.5時 = 5.5*60 = 330分,
0786分+330分 = 01116
再換算回來 = (1116/60)時(1116%60)分 = 1836

最後要輸出時只要判斷是否有大於12時,就知道要輸出pm還是am了!
但要注意的是! 0:05 a.m.要換成 12:05 a.m.喔
--------------------------------------------------


/* 20150929
 * hanting
 * UVa 10371 Time Zones
 * C++
 */
#include <iostream>
#include <map>
#include <sstream>
#include <iomanip> //setw,setfill
#include <cstring> //strtok
#include <cstdlib> //atoi
using namespace std;
map<string,double> Map;
void init()
{
    Map["UTC"]=0;
    Map["GMT"]=0;
    Map["BST"]=1;
    Map["IST"]=1;
    Map["WET"]=0;
    Map["WEST"]=1;
    Map["CET"]=1;
    Map["CEST"]=2;
    Map["EET"]=2;
    Map["EEST"]=3;
    Map["MSK"]=3;
    Map["MSD"]=4;
    Map["AST"]=-4;
    Map["ADT"]=-3;
    Map["NST"]=-3.5;
    Map["NDT"]=-2.5;
    Map["EST"]=-5;
    Map["EDT"]=-4;
    Map["CST"]=-6;
    Map["CDT"]=-5;
    Map["MST"]=-7;
    Map["MDT"]=-6;
    Map["PST"]=-8;
    Map["PDT"]=-7;
    Map["HST"]=-10;
    Map["AKST"]=-9;
    Map["AKDT"]=-8;
    Map["AEST"]=10;
    Map["AEDT"]=11;
    Map["ACST"]=9.5;
    Map["ACDT"]=10.5;
    Map["AWST"]=8;
}
struct Time
{
    int hour,minute;
    Time():hour(0),minute(0){}
    void operator+=(int a)
    {
        hour+=a;
        hour=(hour+24)%24;
    }
    Time operator+(double d)
    {
        Time result;
        int tmp=minute+(hour+24)*60+d*60;
        result.minute=(tmp)%60;
        result.hour=(tmp/60)%24;
        return result;
    }
    friend istream& operator>>(istream& in,Time &t)
    {
        string cur;
        in>>cur;
        if(cur=="noon")
        {
            t.hour=12;
            t.minute=0;
        }
        else if(cur=="midnight")
        {
            t.hour=0;
            t.minute=0;
        }
        else
        {
            //將12:03分成12和3
            char *pch=strtok((char*)cur.c_str(),":");
            t.hour=atoi(pch);
            pch=strtok(NULL,":");
            t.minute=atoi(pch);
        }
        return in;
    }
    friend ostream& operator<<(ostream& out,Time &t)
    {
        if(t.hour==12 and t.minute==0) out<<"noon";
        else if(t.hour==0 and t.minute==0) out<<"midnight";
        else
        {
            if(t.hour>=12) out<<(t.hour==12 ? 12:t.hour-12)<<":"<<setw(2)<<setfill('0')<<t.minute<<" p.m.";
            else out<<(t.hour==0 ? 12:t.hour)<<":"<<setw(2)<<setfill('0')<<t.minute<<" a.m.";
        }
        return out;
    }
};
int main()
{
    init();
    int caseN;
    cin>>caseN;
    cin.get();
    while(caseN--)
    {
        string str;
        getline(cin,str);
        stringstream sin(str);
        Time cur;
        string ampm;
        string timeZone[2];
        sin>>cur;
        if(cur.minute==0 and (cur.hour==0 or cur.hour==12))//noon,midnight
            sin>>timeZone[0]>>timeZone[1];
        else
        {
            sin>>ampm>>timeZone[0]>>timeZone[1];
            if(ampm=="p.m." and cur.hour!=12) cur+=12;
            else if(ampm=="a.m." and cur.hour==12) cur.hour=0;
        }
        double d=(Map[timeZone[1] ]-Map[timeZone[0] ]);
        Time ans=cur+d;
        cout<<ans<<endl;
    }
    return 0;
}

[UVA] 288 - Arithmetic Operations With Large Integers

題意:
大數運算,
運算元只有+ - * 還有**(指數),
輸入測資的運算子都是正數
所以不會有像 -2+2 這樣的測資
但是像 2-2 這樣的測資是可以的喔

還有指數是由後面往前算
所以2**2**3 = 2**(2**3) = 2**8 = 256
0**0=1,
0**0**0 = 0**(0**0) = 0**1 = 0
--------------------------------------------------

我的作法:
我是用C++..好辛苦
首先要先將輸入的柿子做分割,
分割成運算元運算子兩堆
並分別用陣列存取,
例如:
12345678*129876+2**1993
變成
12345678 129876 2 1993

* + **

運算要先從指數開始做,再做乘,最後做加和減
舉個例子:
1**2+3*4+5*6-7**0
運算7**0,(指數要從後面開始做)
然後將運算結果放回式子,1**2+3*4+5*6-1
然後運算1**2,
一樣將運算結果放回式子,1+3*4+5*6-1
指數做完換做乘法,
1+12+5*6-1
1+12+30-1
乘做完最後做加和減
13+30-1
43-1
42

要拿一個運算子和兩個運算元出來做運算,就是從剛剛那兩個陣列去拿,
例如在運算子的陣列裡,[6]="**",
而相對應的運算元的陣列中,[6]和[7]就是 和 0 ,也就是要做運算的兩個運算元!
注意做完運算後要把那兩個運算元和那個運算子刪掉,
並將運算結果再放回運算元陣列!

再來就是自訂大數型別了,
我使用1個大陣列,
最多3000位數,所以可以開750個格子就好,
每個格子存4個位數(10000進位),
例如:數字1234567890,
陣列[0][1][2]分別存[ 7890 ] [ 3456 ] [ 12 ] 。
還有需要一個記號表示該大數的正負。

重載有用到的運算子,
+ ,- ,* ,^(指數) ,<

在處理運算元有幾點需要注意的
不管做哪個運算,最後運算完都需要進位
需要注意正負數
      +:
          A(正)+B(正)直接做A+B,
          A(負)+B(負)直接做A+B,最後結果再作負數記號,
          A(負)+B(正)可以換成B-A
          不會有A(正)+B(負)的情形
      -:
          A-B要先判斷A跟B誰比較大,然後用大的減小的,再看有沒有負號
      *:
          正*正=正,負*負=正,正*負=負,負*正=負
判斷A<B,先判斷正負數後,然後判斷位數,最後再從最高位數開始判斷
輸出時除了最高位數的數字以外,小於1000的都要補0

--------------------------------------------------

/* 20150929
 * hanting
 * UVa 288 - Arithmetic Operations With Large Integers
 * C++
 */
#include <iostream>
#include <vector>
#include <cstdlib> //atoi
#include <cstring> //strtok
#include <iomanip> //setw ,setfill
using namespace std;
#define BNum B.Num
#define Bdigit B.digit
struct BigInteger
{
    bool sign;//1(-),0(+)
    int Num[1001];
    int digit;
    BigInteger(string num="");
    BigInteger operator+(BigInteger &B);
    BigInteger operator-(BigInteger &B);
    BigInteger operator*(BigInteger &B);
    BigInteger operator^(BigInteger &B);
    bool operator<(BigInteger &B);
    bool IsZero();
    void operator--(int);
    void operator*=(BigInteger &B);
    void CountDigit();
    friend ostream& operator<<(ostream& out,BigInteger &B);
};
int main()
{
    string expression,tmp;
    while(cin>>expression)
    {
        copy(expression.begin(),expression.end(),back_inserter(tmp));
        vector<BigInteger> num;
        vector<string> op;
        char *pch=strtok((char*)expression.c_str(),"+-*");
        while(pch)
        {
            num.push_back(BigInteger(pch));
            pch=strtok(NULL,"+-*");
        }
        expression=tmp;

        pch=strtok((char*)expression.c_str(),"0123456789");
        while(pch)
        {
            op.push_back(pch);
            pch=strtok(NULL,"0123456789");
        }
        for(int i=op.size()-1;i>=0;i--)
        {
            if(op[i]=="**")
            {
                num[i]=num[i]^num[i+1];
                op.erase(op.begin()+i);
                num.erase(num.begin()+i+1);
            }
        }
        for(int i=0;i<op.size();i++)
        {
            if(op[i]=="*")
            {
                num[i]=num[i]*num[i+1];
                num.erase(num.begin()+i+1);
                op.erase(op.begin()+i);
                i--;
            }
        }
        for(int i=0;i<op.size();i++)
        {
            if(op[i]=="+") num[i]=num[i]+num[i+1];
            else if(op[i]=="-")num[i]=num[i]-num[i+1];
            num.erase(num.begin()+i+1);
            op.erase(op.begin()+i);
            i--;
        }
        cout<<num[0]<<endl;
        tmp.clear();
    }
    return 0;
}
BigInteger::BigInteger(string str):sign(0),digit(0),Num{0}
{
    while(str.size()>4)
    {
        string tmp=str.substr(str.size()-4);
        Num[digit++]=atoi(tmp.c_str());
        str.erase(str.size()-4,4);
    }
    if(str.size())
    {
        Num[digit++]=atoi(str.c_str());
    }
}
void BigInteger::CountDigit()
{
    for(int i=1000;i>=0;i--)
    {
        if(Num[i]!=0)
        {
            digit=i+1;
            return ;
        }
    }
}

void BigInteger::operator--(int)
{
    if(digit<=0) return ;
    Num[digit-1]--;
    for(int i=0;i<digit-1;i++)
    {
        Num[i]+=9999;
    }
    CountDigit();
    for(int i=1;i<digit;i++)
    {
        Num[i]+=Num[i-1]/10000;
        Num[i-1]%=10000;
    }
    CountDigit();
}
void BigInteger::operator*=(BigInteger &B)
{
    *this=(*this)*B;
}
bool BigInteger::IsZero()
{
    return digit==1 and Num[0]==0;
}
bool BigInteger::operator<(BigInteger &B)
{
    if(sign==B.sign)
    {
        if(sign==0)//都是正數
        {
            if(digit<Bdigit) return true;
            else if(digit==Bdigit)
            {
                for(int i=digit-1;i>=0;i--)
                {
                    if(Num[i]<BNum[i]) return true;
                    else if(Num[i]==BNum[i]) continue;
                    else return false;
                }
            }
            else return false;
        }
        else//都是負數
        {
            if(digit<Bdigit) return false;
            else if(digit==Bdigit)
            {
                for(int i=digit-1;i>=0;i--)
                {
                    if(Num[i]<BNum[i]) return false;
                    else if(Num[i]==BNum[i]) continue;
                    else return true;
                }
            }
            else return true;
        }
    }
    else if(sign==1 and B.sign==0)//負數<正數
    {
        return true;
    }
    else//正數<負數
    {
        return false;
    }
}
BigInteger BigInteger::operator+(BigInteger &B)
{
    BigInteger result;
    if(sign==B.sign)
    {
        for(int i=0;i<digit or i<Bdigit;i++)
        {
            result.Num[i]+=Num[i]+BNum[i];
            result.Num[i+1]+=result.Num[i]/10000;
            result.Num[i]%=10000;
        }
    }
    else//-3+2
    {
        this->sign=0;
        result=B-(*this);
    }
    result.CountDigit();
    return result;
}
BigInteger BigInteger::operator-(BigInteger &B)
{
    BigInteger result;
    if(*this<B)
    {
        result.sign=1;//負數
        if(Bdigit>1)
        {
            BNum[Bdigit-1]--;
            for(int i=Bdigit-2;i>0;i--)
            {
                BNum[i]+=9999;
            }
            BNum[0]+=10000;
            for(int i=0;i<Bdigit;i++)
            {
                if(sign==0) result.Num[i]=BNum[i]-Num[i];
                else result.Num[i]=BNum[i]+Num[i];
            }
        }
        else
        {
            if(sign==0)result.Num[0]=BNum[0]-Num[0];
            else result.Num[0]=BNum[0]+Num[0];
        }
    }
    else
    {
        if(digit>1)
        {
            Num[digit-1]--;
            for(int i=digit-2;i>0;i--)
            {
                Num[i]+=9999;
            }
            Num[0]+=10000;
            for(int i=0;i<digit;i++)
            {
                result.Num[i]=Num[i]-BNum[i];
            }
        }
        else
        {
            result.Num[0]=Num[0]-BNum[0];
        }
    }
    for(int i=1;i<Bdigit or i<digit;i++)
    {
        result.Num[i]+=result.Num[i-1]/10000;
        result.Num[i-1]%=10000;
    }
    result.CountDigit();
    return result;
}
BigInteger BigInteger::operator*(BigInteger &B)
{
    BigInteger result;
    if(sign) result.sign=!result.sign;
    if(B.sign) result.sign=!result.sign;
    for(int i=0;i<digit;i++)
    {
        for(int j=0;j<Bdigit;j++)
        {
            result.Num[i+j]+=Num[i]*BNum[j];
        }
    }
    for(int i=1;i<digit+Bdigit;i++)
    {
        result.Num[i]+=result.Num[i-1]/10000;
        result.Num[i-1]%=10000;
    }
    result.CountDigit();
    return result;
}
BigInteger BigInteger::operator^(BigInteger &B)
{
    BigInteger result("1");
    while(!B.IsZero())
    {
        result*=(*this);
        B--;

    }
    return result;
}

ostream& operator<<(ostream& out,BigInteger &B)
{
    if(Bdigit==0) out<<0;
    else
    {
        if(B.sign) cout<<"-";
        if(Bdigit) cout<<BNum[Bdigit-1];
        for(int i=Bdigit-2;i>=0;i--)
        {
            out<<setw(4)<<setfill('0')<<BNum[i];
        }
    }
    return out;
}

2015年9月28日 星期一

[UVA] 860 - Entropy Text Analyzer

題意:
給你一篇文章,分別求出 λ , ET , Erel ,題目有給公式!

其中 λ 是文章總共有多少單字。
Pi 是每一種單字出現的次數。

--------------------------------------------------

方法:
要把所有單字都轉成小寫!
然後可以用二元組去存,<string,int>分別代表單字與其出現的次數,
然後就代公式囉!
注意 ET 和 Erel 要用浮點數去存,
還有don't 不等於 dont 喔,這樣算兩個不同的單字!
yeah

--------------------------------------------------


/* 20150928
 * hanting
 * UVa 860 - Entropy Text Analyzer
 * C++
 */
#include <iostream>
#include <cstring> //strtok
#include <map>
#include <cmath> //log
#include <iomanip> //setprecision
using namespace std;
string normalize(string str)
{
    string tmp="";
    for(int i=0;i<str.size();i++)
    {
        tmp+=tolower(str[i]);
    }
    return tmp;
}
int main()
{
    string str;
    while(getline(cin,str) and str!="****END_OF_INPUT****")
    {
        int lambda=0;
        double ET=0,Erel=0,Emax=0;
        map<string,int> Map;
        char *pch=strtok((char*)str.c_str(),",.:;!?\"() ");
        while(pch)
        {
            string tmp;
            tmp=normalize(pch);
            Map[tmp]++;
            lambda++;
            pch=strtok(NULL,",.:;!?\"() ");
        }
        while(getline(cin,str) and str!="****END_OF_TEXT****")
        {
            pch=strtok((char*)str.c_str(),",.:;!?\"() ");
            while(pch)
            {
                string tmp=normalize(pch);
                Map[tmp]++;
                lambda++;
                pch=strtok(NULL,",.:;!?\"() ");
            }
        }
        double sum=0;
        for(map<string,int>::iterator it=Map.begin();it!=Map.end();++it)
        {
            int pi=it->second;
            sum+=(pi)*(log10(lambda)-log10(pi));
        }
        ET=sum/lambda;

        Emax=log10(lambda);
        Erel=ET/Emax*100;

        cout<<lambda;
        cout<<fixed<<setprecision(1)<<" "<<ET<<" ";
        cout<<fixed<<setprecision(0)<<Erel<<endl;
    }
    return 0;
}

2015年9月27日 星期日

[UVA] 175 - Keywords

題意:
給幾個題材(profile),每個題材都有2個以上的單字,
再給定幾個標題(title),每個標題可能有用到某個題材的單字,
單字每個字母皆視為小寫
不是字母都略過
例如:
(Mis)-Conceptions == misconceptions
Metaphor in 1984, Concepts == metaphor in concepts
問:每個題材有被哪些標題取用兩個單字以上,且兩單字中間穿插的字串數在限制內

範例輸入
P: 0 rock art
P: 3 concepts conceptions
P: 1   art rock   metaphor concepts
T: Rock Art of the Maori|
T: Jazz and Rock - Art Brubeck and Elvis Presley|
T: Don't Rock --- the Boat as Metaphor in 1984, Concepts
   and (Mis)-Conceptions of an Art Historian.|
T: Carved in Rock, The Art and Craft of making promises
   believable when your `phone bills have gone
   through the roof|
#
P表示profile,數字表示被取用的兩個單字間有多少個其他單字穿插
T表示Title,最後以字元'|'表示結束這個title輸入
字元 # 為結束測資輸入

範例輸出
1: 1,2
2:
3: 1,2,3,4

1: 1,2表示
  profile1有被title1 和title2取用2個單字以上,
  且兩個單字間沒有其他單字穿插,
  title1: Rock Art of the Maori|
  title2: Jazz and Rock - Art Brubeck and Elvis Presley|
  Rock和Art間的'-'字元不是字母所以略過

2: 表示
  profile2的單字都沒有被任何title取用2個單字以上

3: 1,2,3,4表示
  profile3的單字有被title1 和 title2 和 title3 和 title4取用2個單字以上,
 且兩個單字間最多只有1個單字穿插
 title1: Rock Art of the Maori|
 title2: Jazz and Rock - Art Brubeck and Elvis Presley|
 title3: Don't Rock --- the Boat as Metaphor in 1984, Concepts
          and (Mis)-Conceptions of an Art Historian.|
 title4: Carved in Rock, The Art and Craft of making promises
          believable when your `phone bills have gone
          through the roof|


注意!
P1: 0 apple banana apple
P2: 0 apple banana

T1: apple apple只有P1符合,P2不符合(P2只有一顆apple不夠)
--------------------------------------------------

方法:
先做預處理,將每個字串做編號,
要判斷第j個title是否有用到第i個profile的兩個單字以上,
就是title[j]中的每個單字哪些是profile[i]有的,先做記號,
只要任兩個相鄰記號小於profile[i]的限制距離,
表示profile[i]有被title[j]取用到。

具體作法可以找到一個profile[i]的單字就先把profile[i]的那個單字erase,
避免重複取,最後找完再復原。


**************************************************


/* 20150927
 * hanting
 * UVa 175 - Keywords
 * C++
 */
#include <iostream>
#include <vector>
#include <map>
#include <algorithm> //find
using namespace std;
vector<string> store;
map<string,int> Map;
int ID(string str)//為字串做編號
{
    if(Map.count(str)) return Map[str];
    else
    {
        store.push_back(str);
        return Map[str]=store.size()-1;
    }
}
void normalize(string &str)//將不是字母的字元去掉
{
    string tmp="";
    for(int i=0;i<str.size();i++)
    {
        if(isalpha(str[i])) tmp+=tolower(str[i]);
    }
    str=tmp;
}
vector<int> Distance(51);
vector<int> profile[51];
vector<int> title[51];
bool Find(int i,int id)//在第i個 profile 可以找到編號id
{
    vector<int>::iterator it=find(profile[i].begin(),profile[i].end(),id);
    if(it!=profile[i].end())
    {
        profile[i].erase(it);
        return true;
    }
    return false;
}
bool Selected(int i,int j)//第i個 profile 的字串有被第j個 Title選到,
{
    int last=-1,cur=-10000;
    for(int k=0;k<title[j].size();k++) //第j個 title的第k個字串
    {
        if(last>=0 and cur>=0 and title[j][k]==title[j][cur])
        {
            cur=k;
        }
        if(Find(i,title[j][k]))
        {
            last=cur;
            cur=k;
            if((cur-last)<=Distance[i]+1) return true;
            else if(last>=0) profile[i].push_back(title[j][last]);
        }
    }
    return false;
}
int main()
{
    string str;
    int Pidx=1;
    int Tidx=1;
    while(cin>>str and str[0]!='#')//讀P或T
    {
        if(str[0]=='P')
        {
            int dis;
            cin>>dis;
            Distance[Pidx]=dis;
            while(cin>>str)
            {
                profile[Pidx].push_back(ID(str));
                if(cin.get()=='\n') break;
            }
            Pidx++;
        }
        else//if(str[0]=='T')
        {
            while(cin>>str)
            {
                bool terminate=str[str.size()-1]=='|';
                normalize(str);
                if(str.size()==0) continue;
                title[Tidx].push_back(ID(str));
                if(terminate) break;
            }
            Tidx++;
        }
    }/*end of input*/


    vector<int> ans[51];
    for(int i=1;i<Pidx;i++)
    {
        for(int j=1;j<Tidx;j++)
        {
            vector<int> tmp(profile[i].begin(),profile[i].end());
            if(Selected(i,j)) ans[i].push_back(j);
            profile[i]=tmp;
        }
    }

    for(int i=1;i<Pidx;i++)
    {
        cout<<i<<": ";
        for(int j=0;j+1<ans[i].size();j++)
        {
            cout<<ans[i][j]<<",";
        }
        if(ans[i].size()) cout<<ans[i].back();
        cout<<endl;
    }
    return 0;
}

--------------------------------------------------
input.txt
output:
1: 1,2,3
2: 1,2,3

2015年9月23日 星期三

[UVA] 812 - Trade on Verweggistan

題意:
輸入數筆測資,
輸入N個數列,每個數列第一個數字表示該數列的元素數量,
每個數列的每個數字表示以多少錢進購產品,每個產品再以10元賣給荷蘭,
所以要求的是最大利潤,
以及要進購多少產品的前10個可能的值。
進購得產品是有依序的,也就是說要先進購第一個產品才能進購第二個產品。

測資間要空行,最後一筆測資後面不需要空行。

--------------------------------------------------

方法:
先將讀進來的每個數字改為進購第 i 個產品可得的利潤,
進而求出該數列最大可得利潤,
最後將每個數列的最大利潤相加總就是題目的第一個所求。
可以得知每個數列的最大利潤是在進購多少產品,
所以可以先記錄起來,
例如:
第一個數列有三個6,11,9,分別在進購第1個,第2個,第3個的利潤是
4,3,4
表示在連續進購 1 個或連續進購 3 個產品時可以得到最大利潤4,
那就將1 和 3記錄起來當記錄值,表示該數列可以進購1或3個都可以得到最大利潤,
最後用遞迴將每個數列的紀錄值去做組合,最後排序後輸出不重複的前10個數字。


注意!當最大利潤是0時,進購的產品數量也可以是0。

--------------------------------------------------

/* 20150923
 * hanting
 * UVa 812 - Trade on Verweggistan
 * C++
 */
#include <iostream>
#include <vector>
#include <cstring> //memset
#include <algorithm> //sort
#include <set>
using namespace std;
void DFS(vector<int> *vec,int N,set<int> &Set,int sum,int cur)
{
    if(cur==N)
    {
        Set.insert(sum);
    }
    else
    {
        for(int i=0;i<vec[cur].size();i++)
        {
            int tmp=vec[cur][i];
            DFS(vec,N,Set,sum+tmp,cur+1);
        }
    }
}
int main()
{
    int N;
    int caseN=0;
    while(cin>>N and N)
    {
        vector<int> profit[N];
        vector<int> NumToBuy[N];
        int Max[N];
        memset(Max,0,sizeof(Max));
        int MaximumProfit=0;
        for(int i=0;i<N;i++)
        {
            int numN;
            cin>>numN;
            for(int j=0;j<numN;j++)
            {
                int num;
                cin>>num;
                profit[i].push_back(10-num);
                if(j) profit[i][j]+=profit[i][j-1];
                Max[i]=max(Max[i],profit[i][j]);
            }
            if(Max[i]==0) NumToBuy[i].push_back(0);
            for(int j=0;j<numN;j++)
            {
                if(profit[i][j]==Max[i])
                    NumToBuy[i].push_back(j+1);
            }
            MaximumProfit+=Max[i];
        }
        set<int> Set;
        DFS(NumToBuy,N,Set,0,0);

        if(caseN) cout<<endl;
        cout<<"Workyards "<<++caseN<<endl;
        cout<<"Maximum profit is "<<MaximumProfit<<"."<<endl;
        cout<<"Number of pruls to buy:";
        int cnt=0;//輸出前10個即可
        for(set<int>::iterator it=Set.begin();it!=Set.end() and cnt<10;++it,cnt++)
        {
            cout<<" "<<*it;
        }
        cout<<endl;

    }
    return 0;
}

2015年9月22日 星期二

[UVA] 191 - Intersection

題意:
給一條線段和一個四方形,
判斷線段是否與四方形有香蕉。

--------------------------------------------------

方法:
注意喔!四方形他是給你對角兩點,但不一定是左上右下,要自己判斷!

線段有起始點和終點,
有兩點就可以求出線段斜率,斜率 = (y1-y0)/(x1-x0) = (終點y-起點y)/(終點x-起點x)
垂直線要另外判斷,斜率用很大的數字表示。

先判斷該線段是否可能相交四方形,
線段的兩點x要與四邊形的左右x交疊,
兩點y要與四邊形的上下交疊,

再來判斷線段有沒有交四邊形,
假設線段斜率是m,
斜率為m的線段有無限條,
但是通過起點終點的只有一條,而直線方程式有一常數(位移量),y=mx+a的a就是常數
現在將四邊形的四個頂點帶進去斜率為m的線段都會各自得到1個常數,
若四個常數有>=a也有<=a則表示四個點分布在線段兩邊,也就是線段跟四邊形有相交。


--------------------------------------------------

/* 20150922
 * hanting
 * UVa 191 - Intersection
 * C++
 */
#include <iostream>
using namespace std;
struct point
{
    double x,y;
    point(double _x=0,double _y=0):x(_x),y(_y){}
    friend istream& operator>>(istream& in,point &p)
    {
        in>>p.x>>p.y;
        return in;
    }
};
struct rectangle
{
    point topLeft,bottomRight;
    point topRight,bottomLeft;
    point v1,v2;
    friend istream& operator>>(istream& in,rectangle &r)
    {
        in>>r.v1>>r.v2;
        r.Build();
        return in;
    }
    void Build()//建立四邊形四個頂點
    {
        if(v1.x>v2.x)
        {
            if(v1.y>v2.y)
            {
                topRight=v1;
                bottomLeft=v2;

                topLeft=point(bottomLeft.x,topRight.y);
                bottomRight=point(topRight.x,bottomLeft.y);
            }
            else
            {
                bottomRight=v1;
                topLeft=v2;

                bottomLeft=point(topLeft.x,bottomRight.y);
                topRight=point(bottomRight.x,topLeft.y);
            }
        }
        else
        {
            if(v1.y>v2.y)
            {
                topLeft=v1;
                bottomRight=v2;

                topRight=point(bottomRight.x,topLeft.y);
                bottomLeft=point(topLeft.x,bottomRight.y);
            }
            else
            {
                bottomLeft=v1;
                topRight=v2;

                bottomRight=point(topRight.x,bottomLeft.y);
                topLeft=point(bottomLeft.x,topRight.y);
            }
        }
    }
    inline bool xCover(point &start,point &End)
    {
        return !(start.x>topRight.x and End.x>topRight.x) and !(start.x<topLeft.x and End.x<topLeft.x);
    }
    inline bool yCover(point &start,point &End)
    {
        return !(start.y>topRight.y and End.y>topRight.y) and !(start.y<bottomLeft.y and End.y<bottomLeft.y);
    }
};
struct line
{
    point start,End;
    double m,a;//y=mx-a
    friend istream& operator>>(istream& in,line &l)
    {
        in>>l.start>>l.End;
        l.BuildEquation();
        return in;
    }
    void BuildEquation()
    {
        if(start.x==End.x)
            m=0x3fffffff;
        else
            m=(start.y-End.y)/(start.x-End.x);
        a=m*start.x-start.y;//a=mx-y
    }
    double equation(point &p)
    {
        return m*p.x-p.y;
    }
    bool intersect(rectangle &rec)
    {
        if(!rec.xCover(start,End) or !rec.yCover(start,End))
            return false;
        if(m==0x3fffffff) return true;
        double e1,e2,e3,e4;
        e1=equation(rec.topLeft);
        e2=equation(rec.topRight);
        e3=equation(rec.bottomLeft);
        e4=equation(rec.bottomRight);
        bool positive,negative;//判斷四個頂點是否在線段左右
        positive=e1>=a or e2>=a or e3>=a or e4>=a;
        negative=e1<=a or e2<=a or e3<=a or e4<=a;
        return positive and negative;
    }
};
int main()
{
    int caseN;
    cin>>caseN;
    while(caseN--)
    {
        line l;
        rectangle rec;
        cin>>l>>rec;
        cout<<(l.intersect(rec) ? 'T':'F')<<endl;
    }
    return 0;
}


--------------------------------------------------

input.txt
output.txt

[UVA] 10221 - Satellites

題意:
如圖,給你圓上兩點的夾角,和點與圓中心的距離,
求出兩點的弧長與弦長。

--------------------------------------------------

方法:
如果夾角超過180度則用360去減夾角,
例如兩點夾角200度,也就是說兩點其實是夾角160度。
60 degree =  1 min

弧長:圓周長*(給的角度/360)。

弦長:有邊有角度,餘弦定理


注意! PI要用2*acos(0)


--------------------------------------------------

/* 20150922
 * hanting
 * UVa 10221 - Satellites
 * C++
 */
#include <iostream>
#include <cmath>//cos,sqrt
#include <iomanip>//setprecision
using namespace std;
#define PI 2*acos(0)
int main()
{
    double s,a;
    string str;
    while(cin>>s>>a>>str)
    {
        if(a>180) a=360-a;
        double r=6440+s;
        double arc,chord;
        if(str=="min")
        {
            a/=60; //degree=min/60
        }
        arc=2*PI*r*a/360.;
        chord=sqrt(r*r+r*r-2*r*r*cos(PI*a/180.));
        cout<<fixed<<setprecision(6)<<arc<<" "<<chord<<endl;
    }
    return 0;
}

[UVA] 478 - Points in Figures: Rectangles, Circles, and Triangles

題意:
輸入三種圖形,
再輸入點,判斷該點在哪幾個圖形裡面(不包括邊上)。
r是rectangle 四方形(輸入左上和右下的點)
c是circle 圓形(輸入中心點和半徑)
t是triangle 三角形(輸入三個頂點)

--------------------------------------------------

方法:
四方形:
    只要判斷x是否在四方形的左右兩邊裡面,y是否在四方形的上下兩邊。
圓形:
    判斷點到圓中心的距離是否小於半徑。
三角形:
    該點連接到三角形三個頂點可以切成三個三角形,
    任三點可以形成兩個向量,兩個向量可以形成一個三角形,
    所以!如果三個小三角形面積總和等於原始大三角形面積,則點在三角形內
    另外需要注意的是,其中一個小三角形不能為零(若為零表示點在邊上)。
--------------------------------------------------

/* 20150922
 * hanting
 * UVa 478 - Points in Figures: Rectangles, Circles, and Triangles
 * C++
 */
#include <iostream>
#include <vector>
#include <cstdlib>//fabs
#include <cmath>//sqrt
#include <algorithm>//sort
using namespace std;
#define DISTANCE(a,b) sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y))
#define VEC(a,b) point(b.x-a.x,b.y-a.y)
#define AREA(a,b) fabs((a.x*b.y-a.y*b.x)/2)
struct point
{
    double x,y;
    point(double _x=0,double _y=0):x(_x),y(_y){}
    friend istream& operator>>(istream& in,point &p)
    {
        in>>p.x>>p.y;
        return in;
    }
    bool operator!=(double d)
    {
        return x!=9999.9 and y!=9999.9;
    }
};
struct rectangle
{
    int id;
    point upLeft,lowRight;
    friend istream& operator>>(istream& in,rectangle &rec)
    {
        in>>rec.upLeft>>rec.lowRight;
        return in;
    }
    bool contain(const point &p)
    {
        return p.x>upLeft.x and p.x<lowRight.x and p.y>lowRight.y and p.y<upLeft.y;
    }
};
struct circle
{
    int id;
    point center;
    double radius;
    friend istream& operator>>(istream& in,circle &cir)
    {
        in>>cir.center>>cir.radius;
        return in;
    }
    bool contain(const point &p)
    {
        return DISTANCE(p,center)<radius;
    }
};
struct triangle
{
    int id;
    point v1,v2,v3;
    friend istream& operator>>(istream& in,triangle &tri)
    {
        in>>tri.v1>>tri.v2>>tri.v3;
        return in;
    }
    bool contain(const point &p)
    {
        double a1,a2,a3;
        a1=AREA(VEC(p,v1),VEC(p,v2));
        a2=AREA(VEC(p,v2),VEC(p,v3));
        a3=AREA(VEC(p,v1),VEC(p,v3));
        return a1 and a2 and a3 and (a1+a2+a3)- AREA(VEC(v1,v2),VEC(v1,v3))<1e-8;
    }
};
int main()
{
    char ch;
    vector<rectangle> rec;
    vector<circle> cir;
    vector<triangle> tri;
    int idN=1;
    while(cin>>ch and ch!='*')
    {
        if(ch=='r')
        {
            rectangle tmp;
            cin>>tmp;
            tmp.id=idN;
            rec.push_back(tmp);
        }
        else if(ch=='c')
        {
            circle tmp;
            cin>>tmp;
            tmp.id=idN;
            cir.push_back(tmp);
        }
        else//if(ch=='t)
        {
            triangle tmp;
            cin>>tmp;
            tmp.id=idN;
            tri.push_back(tmp);
        }
        idN++;
    }

    point p;
    int pointN=1;
    while(cin>>p and p!=9999.9)
    {
        vector<int> ans;
        sort(ans.begin(),ans.end());
        for(int i=0;i<rec.size();i++)
        {
            if(rec[i].contain(p))
            {
                ans.push_back(rec[i].id);
            }
        }
        for(int i=0;i<cir.size();i++)
        {
            if(cir[i].contain(p))
            {
                ans.push_back(cir[i].id);
            }
        }
        for(int i=0;i<tri.size();i++)
        {
            if(tri[i].contain(p))
            {
                ans.push_back(tri[i].id);
            }
        }
        if(ans.size())
        {
            for(int i=0;i<ans.size();i++)
            {
                cout<<"Point "<<pointN<<" is contained in figure "<<ans[i]<<endl;
            }
        }
        else
        {
            cout<<"Point "<<pointN<<" is not contained in any figure"<<endl;
        }
        pointN++;
    }
    return 0;
}

2015年9月5日 星期六

[UVA] 11059 - Maximum Product

題意:
求最大連乘積。
如果最大連乘積小於0要輸出0。
--------------------------------------------------

方法:
因為資料量不多,
可以枚舉起點和終點,
計算起點到終點的連乘積。

注意!要用long long!

--------------------------------------------------


/* 20150906
 * hanting
 * UVa 11059 - Maximum Product
 * C++
 */
#include <iostream>
using namespace std;
int main()
{
    int N;
    int caseN=1;
    while(cin>>N)
    {
        int num[N];
        for(int i=0;i<N;i++)
        {
            cin>>num[i];
        }
        long long Max=0;//Max最小是0
        for(int i=0;i<N;i++)//start
        {
            for(int j=i+1;j<=N;j++)//end
            {
                long long sum=num[i];
                for(int k=i+1;k<j;k++)
                {
                    sum*=num[k];
                }
                if(Max<sum) Max=sum;
            }
        }
        cout<<"Case #"<<caseN++<<": The maximum product is "<<Max<<"."<<endl<<endl;
    }
    return 0;
}

[UVA] 725 - Division

題意:
輸入N,找到所有解可以滿足
abcde / fghij = N,
其中abcde fghij 是0~9的數字,每個數字都要用到,
不能重複!
測資間要有空行,最後一筆後面不用空行。
--------------------------------------------------

方法:
N去乘以除數得到被除數,
分別去判斷除數和被除數是否有用到重複的數字,
除數可以用for迴圈從1234開始到100000/N,
(1234是最小不重複數字的數,注意! int 的 1234 不等於 int 的 01234 喔!)

--------------------------------------------------


/* 20150906
 * hanting
 * UVa 725 - Division
 * C++
 */
#include <iostream>
using namespace std;
bool check(int n,int p)
{
    if(p<10000 and n<10000) return false;//除數和被除數不都是0開頭
    int vis[10]={n<10000};
    while(n)
    {
        int m=n%10;
        if(vis[m]) return false;
        else
        {
            vis[m]=true;
            n/=10;
        }
    }
    while(p)
    {
        int m=p%10;
        if(vis[m]) return false;
        else
        {
            vis[m]=true;
            p/=10;
        }
    }
    return true;
}
int main()
{
    int N;
    bool blank=false;
    while(cin>>N and N)
    {
        if(blank++) cout<<endl;
        bool solution=false;
        for(int i=1234;i<100000/N;i++)
        {
            if(check(i,i*N))
            {
                solution=true;
                cout<<i*N<<" / "<<(i<10000 ? "0":"")<<i<<" = "<<N<<endl;
            }
        }
        if(!solution)
        {
            cout<<"There are no solutions for "<<N<<"."<<endl;
        }
    }
    return 0;
}