2016年12月23日 星期五

[UVA] 10721 - Bar Codes

題目連結 → here

題意:

函數BC(n, k, m)為共有 n 個球,現在要分成 k 份,每份不超過 m 個。
然後要用64 bit整數儲存。

==================================================

我的作法:

遞迴方式實作,

BC(7, 4, 3) = 有 7 個球,分成 4 份,每份不超過 3 個,
而 BC(7, 4, 2) = 有 7 個球,分成 4 份,每份不超過 2 個。
有沒有發現呢!
其實每份不超過 3 個的解就是等於每份不超過 2 個的解 + 4份當中有 i 份有 3 個的解。
所以 BC(7, 4, 3) = BC(7, 4, 2)  + 其中1份有3個 + 其中2份有3個 + 其中3份有3個 + 4份都是3個。

  • 其中1份有3個的算法 = BC(7-3, 4-1, 2) * C(4, 1),
  • 其中2份有3個的算法 = BC(7-3*2, 4-2, 2) * C(4, 2),
  • 其中3份有3個的算法 = BC(7-3*3, 4-3, 2) * C(4, 3),
  • 4份都是3個的算法 = BC(7-3*4, 4-4, 2) * C(4, 4)。

但需要注意的幾點是,
當 n <= 0 || k <= 0 || m <= 0時,BC(n, k, m) = 0;
當 n > k*m 或 n < k 時,BC(n, k, m) = 0;
當 n == k*m 或 k ==1 或 m == 1時, BC(n, k, m) = 1;

根據上面結論得到遞迴公式如下,
BC(n, k, m) = BC(n-i*m, k-i, m-1) * C(k, i);


小補充:
根據巴斯卡定理,
C(n, m) = C(n-1, m) + C(n-1, m-1)。

==================================================

程式碼:

2016年12月19日 星期一

[UVA] 10158 - War

題目連結

題意:
a和b是朋友,b和c是朋友,則a和c也是朋友。
a和b是敵人,b和c是敵人,則a和c是朋友。
a和b是朋友,b和c是敵人,則a和c也是敵人。

==================================================
我的作法:
disjoint set,
將一群選出一個代表。
將朋友做union,另外用一個陣列存敵人,只需整群的代表存即可,
在做操作都是從代表去做。
==================================================
程式碼:
/* 題目: UVa 10158 - War
 * Language: C++
 * Created on: 2016年12月19日
 *   Author: hanting
 */
#include <iostream>
#include <vector>
using namespace std;
class DisjointSet
{
    vector<int> rep;
    vector<int> enemy;
    int id;
public:
    void init(int n)
    {
        id = 0;
        rep.assign(n, -1);
        enemy.assign(n, -1);
    }
    int Find(int x)
    {
        if(x < 0) return x;
        if(rep[x] < 0) return x;
        else return rep[x] = Find(rep[x]);
    }
    void Union(int x, int y)
    {
        if(x < 0 || y < 0) return ;
        int fx = Find(x),
            fy = Find(y);
        if(fx != fy)
        {
            if(rep[fx] <= rep[fy])
            {
                rep[fx] += rep[fy];
                rep[fy] = fx;
            }
            else
            {
                rep[fy] += rep[fx];
                rep[fx] = fy;
            }
        }
    }
    bool setFriend(int x, int y)
    {
        int fx = Find(x),
            fy = Find(y);
        if(enemy[fx] == fy) // x和y是敵人關係
        {
            return 0;
        }
        else // 分成x, y各自有不同敵人,或是x和y其中一個有敵人
        {
            Union(x, y);
            if(enemy[fx] != -1 && enemy[fy] != -1)
            {
                Union(enemy[fx], enemy[fy]);
                int fefx = Find(enemy[fx]);
                fx = Find(x);
                enemy[fx] = fefx;
                enemy[fefx] = fx;
            }
            else if(enemy[fx] != -1)
            {
                int efx = enemy[fx];
                fx = Find(x);
                enemy[fx] = efx;
            }
            else if(enemy[fy] != -1)
            {
                int efy = enemy[fy];
                fx = Find(x);
                enemy[fx] = efy;
            }
            return 1;
        }
    }
    bool setEnemy(int x, int y)
    {
        int fx = Find(x),
            fy = Find(y);
        if(fx == fy) // x和y是朋友
        {
            return 0;
        }
        else
        {
            Union(x, enemy[fy]);
            Union(y, enemy[fx]);
            fx = Find(x),
            fy = Find(y);
            enemy[fx] = fy;
            enemy[fy] = fx;
            return 1;
        }

    }
    bool areFriend(int x, int y)
    {
        int fx = Find(x),
            fy = Find(y);
        return fx == fy;
    }
    bool areEnemy(int x, int y)
    {
        int fx = Find(x),
            fy = Find(y);
        return Find(enemy[fx]) == fy;
    }
};
int main()
{
    int nodeN;
    cin >> nodeN;
    int op, s, t;
    DisjointSet dSet;
    dSet.init(nodeN);
    while(cin >> op >> s >> t && op+s+t)
    {
        switch(op)
        {
        case 1:
            if(!dSet.setFriend(s, t))
            {
                cout << -1 << endl;
            }
            break;
        case 2:
            if(!dSet.setEnemy(s, t))
            {
                cout << -1 << endl;
            }
            break;
        case 3:
            cout << dSet.areFriend(s, t) << endl;
            break;
        case 4:
            cout << dSet.areEnemy(s, t) << endl;
            break;
        }
    }
    return 0;
}

2016年12月16日 星期五

[UVA] 10608 - Friends

題目連結

我的做法:
Disjoint set 同一群選一個代表!

==================================================
程式碼:
/* 題目: UVa 10608 - Friends
 * Language: C++
 * Created on: 2016年12月16日
 *   Author: hanting
 */
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
class DisjointSet
{
    vector<int> rep;
public:
    void init(int n)
    {
        rep.assign(n, -1);
    }
    int Find(int x)
    {
        if(rep[x] < 0) return x;
        else return rep[x] = Find(rep[x]);
    }
    void Union(int x, int y)
    {
        int fx = Find(x),
            fy = Find(y);
        if(fx != fy)
        {
            if(rep[fx] <= rep[fy])
            {
                rep[fx] += rep[fy];
                rep[fy] = fx;
            }
            else
            {
                rep[fy] += rep[fx];
                rep[fx] = fy;
            }
        }
    }
    int groupN(int x)
    {
        int fx = Find(x);
        return -rep[fx];
    }
};
int main()
{
    int testCase;
    cin >> testCase;
    while(testCase--)
    {
        DisjointSet dSet;
        int nodeN, edgeN;
        cin >> nodeN >> edgeN;
        dSet.init(nodeN+1);
        int s, t;
        for(int i = 0; i < edgeN; i++)
        {
            //cin >> s >> t;
            scanf("%d%d", &s, &t);
            dSet.Union(s, t);
        }
        int maxi = 0;
        for(int i = 1; i <= nodeN; i++)
        {
            maxi = max(maxi, dSet.groupN(i));
        }
        cout << maxi << endl;
    }
    return 0;
}

2016年12月14日 星期三

[UVA] 10801 - Lift Hopping

題目連結

我的做法:
0到k最短路徑問題,priority_queue實做Dijkstra演算法。

==================================================
程式碼:
/* 題目: UVa 10801 - Lift Hopping
 * Language: C++
 * Created on: 2016年12月14日
 *   Author: hanting
 */
#include <iostream>
#include <sstream>
#include <map>
#include <queue>
using namespace std;
struct Node
{
    int num, dis;
    Node(int _num = 0, int _dis = 0)
    {
        num = _num;
        dis = _dis;
    }
    bool operator() (const Node &node1, const Node &node2)const
    {
        return node1.dis < node2.dis;
    }
};
class Graph
{
private:
    vector<vector<Node> > adj;
public:
    int Dijkstra(int s, int t)
    {
        vector<int> dis(adj.size());
        for(int i = 0; i < adj.size(); i++)
        {
            dis[i] = 0x3fffffff;
        }
        dis[s] = 0;
        priority_queue<Node, vector<Node>, Node > pque;
        pque.push(Node(s, 0));
        while(pque.size())
        {
            int cur = pque.top().num;
            pque.pop();
            for(int i = 0; i < adj[cur].size(); i++)
            {
                Node next = adj[cur][i];
                int u = cur,
                    v = next.num,
                    w = next.dis;
                if(dis[v] > dis[u] + w)
                {
                    dis[v] = dis[u] + w;
                    pque.push(Node(v, dis[v]));
                }
            }
        }
        return dis[t];
    }
    void initNodeN(int nodeN)
    {
        adj.assign(nodeN, vector<Node>());
    }
    void link(int s, int t, int w = 0)
    {
        if(s % 100 == 0) s = 0;
        adj[s].push_back(Node(t, w));2
        adj[t].push_back(Node(s, w));
    }
};
int main()
{
    int elevatorN, k;
    while(cin >> elevatorN >> k)
    {
        vector<int> weight(elevatorN);
        for(int i = 0; i < elevatorN; i++)
        {
            cin >> weight[i];
        }
        Graph graph;
        graph.initNodeN(100*elevatorN);
        cin.get();
        map<int, int> Map;
        for(int i = 0; i < elevatorN; i++)
        {
            string str;
            getline(cin ,str);
            stringstream sin(str);
            int s, t;
            sin >> s;
            Map[100*i+s] = 1;
            for(int j = 100*i+s-100; j >= 0; j -= 100)
            {
                if(Map[j])
                {
                    graph.link(100*i+s, j, 60);
                }
            }
            while(sin >> t)
            {
                graph.link(100*i+s, 100*i+t, (t-s)*weight[i]);
                Map[100*i+t] = 1;
                for(int j = 100*i+t-100; j >= 0; j -= 100)
                {
                    if(Map[j])
                    {
                        graph.link(100*i+t, j, 60);
                    }
                }
                s = t;
            }
        }

        int mini = graph.Dijkstra(0, k);
        for(int i = 1; i < elevatorN; i++)
        {
            mini = min(mini, graph.Dijkstra(0, k+100*i));
        }
        if(mini == 0x3fffffff) cout << "IMPOSSIBLE" << endl;
        else cout << mini << endl;
    }
    return 0;
}

2016年10月13日 星期四

[UVA] 11344 - The Huge One

題目連結

題意:

給一超大整數 N,和幾個int
問這幾個int能不能全部都整除N
可以 -> Wonderful
不行 -> Simple
**************************************************

我的作法:

17 % 5 = ((1%5)*10+7)%5
不需要做大數運算...

小技巧:
[字元轉數字]
字元&15
ex: '8' & 15 = 8
因為數字0到9最多使用4個bit
剛好是字元後4個bit
要看最後4個bit是什麼就是做 &1111 也就是 &15
**************************************************

程式碼:


/* 題目: UVa 11344 - The Huge One
 * Language: C++
 * Created on: 2016年10月14日
 *   Author: hanting
 */
#include <iostream>
using namespace std;
string num;
int numMod(int k)
{
    int remainder = 0;
    for(int i = 0; i < num.size(); i++)
    {
        remainder *= 10;
        remainder += (num[i]&15);
        remainder %= k;
    }
    return remainder;
}
int main()
{
    int testCase;
    cin >> testCase;
    while(testCase--)
    {
        cin >> num;
        int n;
        cin >> n;
        bool wonderful = true;
        for(int i = 0; i < n; i++)
        {
            int k;
            cin >> k;
            if(numMod(k) != 0)
            {
                wonderful = false;
            }
        }
        if(wonderful)
        {
            cout << num << " - Wonderful." << endl;
        }
        else
        {
            cout << num << " - Simple." << endl;
        }
    }
    return 0;
}

2016年10月12日 星期三

[UVA] 12604 - Caesar Cipher

題目連結

題意:

給3個字串,分別為
字元表 (會出現的字元)
明文字串
加密的字串

加密的字串解密後一定要出現恰1個明碼字串,
如果 == 1 就是 unique
如果 > 1 就是 ambiguous
如果 == 0 就是 no solution

加密就是指將明文字串的每個字元變成字元表上的下n個字元,
例如:
字元表
uvanice
明文
ane
加密的明文可能是
niu (shift 1)
icv (shift 2)
cea (shift 3)
依此類推
題目就是要求 n 為多少時,可以在加密字串中恰找到1個加密的明文

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

我的作法:

在母字串中找子字串
在這邊我記錄兩種方法,兩種方法都可以AC
一種是以hash方式,一種是KMP。

hash方式是將子字串丟進hash function得到1個hash值,
再去刷母字串,每次抓連續長度 m 的字串,其中 m = 子字串長度
一樣丟進hash function看是否有等於子字串的hash function。
至於hash function神奇地使用質數次方
f(str) = str[0] * p + str[1] * p^2 + str[2] * p^3 ...
p為質數(但不能為2,測試過會錯,這裡我使用7、37可以過,其他沒有測過)。
這方法神奇就在於字串hash值相同但字串不同的機率非常非常小,
也就是說通常hash值相同都是相同字串!!

KMP的部分可以參考維基百科
簡單說就是先建立failure function,
在比對過程如果不對的話,子字串的指標要回到fail[前一個字元] + 1的位置,
若子字串的指標到了子字串尾巴,就count++,表示在母字串找到一個子字串了,
接著指標回到fail[前一個字元]+1。

兩種效率都很高,時間複雜度都是(n+m) ,hash效率稍微高一點。

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

程式碼:


/* 題目: UVa 12604 - Caesar Cipher
 * Language: C++
 * Created on: 2016年10月12日
 *   Author: hanting
 */
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
unsigned Base = 7; // 任一質數 // 不能2
int countStr(char *str, char *pat)
{
    int cnt = 0;
    unsigned  baseMax = 1;
    unsigned  strHash, patHash;
    strHash = str[0];
    patHash = pat[0];
    for(int i = 1; pat[i]; i++)
    {
        patHash = patHash*Base + pat[i];
        strHash = strHash*Base + str[i];
        baseMax *= Base;
    }
    if(patHash == strHash) cnt++;
    for(int i = strlen(pat), j = 0; str[i]; i++, j++)
    {
        strHash = (strHash - baseMax*str[j]) * Base + str[i];
        if(strHash == patHash) cnt++;
    }
    return cnt;
}
int fail[50005];
int KMP(char *str, char *pat)
{
    /*build failure function*/
    fail[0] = -1;
    int j;
    for(int i = 1; pat[i]; i++)
    {
        j = fail[i-1];
        while(j >= 0 && pat[i] != pat[j+1])
        {
            j = fail[j];
        }
        if(pat[i] == pat[j+1])
        {
            fail[i] = j+1;
        }
        else
        {
            fail[i] = -1;
        }
    }
    /*KMP*/
    int cnt = 0;
    j = 0;
    for(int i = 0; str[i]; i++)
    {
        while(j >= 1 && str[i] != pat[j])
        {
            j = fail[j-1] + 1;
        }
        if(str[i] == pat[j])
        {
            j++;
        }
        if(!pat[j])
        {
            cnt++;
            j = fail[j-1]+1;
        }
    }

    return cnt ;
}
char Alphabet[65], plainText[50005], encryptedText[500005];
int ans[50005];
int main()
{
    int testCase;
    scanf("%d", &testCase);
    while(testCase--)
    {
        int pos[128]; // pos['a'] = 0; pos['w'] = 1;// 表上'a'在第0個位置,下一個是'w'
        scanf("%s%s%s", Alphabet, plainText, encryptedText);
        for(int i = 0; Alphabet[i]; i++)
        {
            pos[Alphabet[i]] = i;
        }
        int AlphaL = strlen(Alphabet);
        Alphabet[AlphaL] = Alphabet[0];
        Alphabet[AlphaL+1] = 0;
        int ansi = 0;
        for(int i = 0; i < AlphaL; i++)
        {
            if(countStr(encryptedText, plainText) == 1)
            //if(KMP(encryptedText, plainText) == 1)
            {
                ans[ansi++] = i;
            }
            for(int j = 0; plainText[j]; j++)
            {
                int k = pos[plainText[j]]; // k在table中第幾個
                plainText[j] = Alphabet[k+1];
            }
        }
        if(ansi == 0)
        {
            puts("no solution");
        }
        else if(ansi == 1)
        {
            printf("unique: %d\n", ans[0]);
        }
        else
        {
            printf("ambiguous: ");
            for(int i = 0; i < ansi-1; i++)
            {
                printf("%d ", ans[i]);
            }
            printf("%d\n", ans[ansi-1]);
        }
    }
    return 0;
}

2016年10月7日 星期五

[UVA] 10245 - The Closest Pair Problem

題目連結

須注意的是距離 = 0 時直接return

*********************************************
程式碼:

/* 題目: UVa 10245 - The Closest Pair Problem
 * Language: C++
 * Created on: 2016年10月07日
 *   Author: hanting
 */
#include <iostream>
#include <vector>
#include <algorithm> //sort, lower_bound
#include <cmath> // sqrt
#include <iomanip> // setprecision
using namespace std;
struct Point
{
    double x, y;
    Point(double _x = 0, double _y = 0)
    {
        x = _x;
        y = _y;
    }
    bool operator < (const Point &p)const
    {
        return x < p.x || (x == p.x && y < p.y);
    }
    friend istream& operator >> (istream& in, Point &p)
    {
        in >> p.x >> p.y;
        return in;
    }
};
bool checkInRange(Point &a, Point &b, double &d) // 判斷是否在需要判斷範圍
{
    return a.y + d >= b.y && a.y - d <= b.y;
}
double dis(Point &a, Point &b)
{
    double x, y;
    x = a.x - b.x;
    y = a.y - b.y;
    return sqrt(x*x + y*y);
}
double ClosestPair(vector<Point>::iterator Begin, vector<Point>::iterator End)
{

    double closest = 0x3fffffff;
    if(Begin+1 == End)
    {
        return closest;
    }
    else if(Begin + 2 == End)
    {
        return dis(*Begin, *(Begin+1));
    }
    double SL, SR;
    SL = ClosestPair(Begin, Begin+(End-Begin)/2);
    SR = ClosestPair(Begin+(End-Begin)/2, End);

    double d, L;
    d = min(SL, SR);
    if(!d) return 0;
    L = (Begin+(End-Begin)/2)->x;
    closest = d;
    for(vector<Point>::iterator it = lower_bound(Begin, End, L-d);
    it != (Begin+(End-Begin)/2); ++it)
    {
        for(vector<Point>::iterator j = (Begin+(End-Begin)/2), jEnd = lower_bound(Begin, End, L+d);
        j != jEnd; j++)
        {
            if(checkInRange(*it, *j, d))
            {
                closest = min(closest, dis(*it, *j));
            }
        }
    }
    return closest;
}
int main()
{
    int pointN;
    while(cin >> pointN && pointN)
    {
        vector<Point> vec;
        for(int i = 0; i < pointN; i++)
        {
            Point tmp;
            cin >> tmp;
            vec.push_back(tmp);
        }
        sort(vec.begin(), vec.end());
        double ans = ClosestPair(vec.begin(), vec.end());
        if(ans < 10000.0)
            cout << fixed << setprecision(4) << ans << endl;
        else
            cout << "INFINITY" << endl;
    }
    return 0;
}

**************************************************
不用Vector且以scanf, printf輸入輸出,時間較快
/* 題目: UVa 10245 - The Closest Pair Problem
 * Language: C++
 * Created on: 2016年10月07日
 *   Author: hanting
 */
#include <iostream>
#include <cstdio>
#include <algorithm> //sort, lower_bound
#include <cmath> // sqrt
#include <iomanip> // setprecision
using namespace std;
struct Point
{
    double x, y;
    Point(double _x = 0, double _y = 0)
    {
        x = _x;
        y = _y;
    }
    bool operator < (const Point &p)const
    {
        return x < p.x || (x == p.x && y < p.y);
    }
};
bool checkInRange(Point &a, Point &b, double &d) // 判斷是否在需要判斷範圍
{
    return a.y + d >= b.y && a.y - d <= b.y;
}
double dis(Point &a, Point &b)
{
    double x, y;
    x = a.x - b.x;
    y = a.y - b.y;
    return sqrt(x*x + y*y);
}
double ClosestPair(Point *Begin, Point *End)
{
    double closest = 0x3fffffff;
    if(Begin+1 == End)
    {
        return closest;
    }
    else if(Begin + 2 == End)
    {
        return dis(*Begin, *(Begin+1));
    }
    double SL, SR;
    SL = ClosestPair(Begin, Begin+(End-Begin)/2);
    SR = ClosestPair(Begin+(End-Begin)/2, End);

    double d, L;
    d = min(SL, SR);
    if(!d) return 0;
    L = (Begin+(End-Begin)/2)->x;
    closest = d;
    for(Point *it = lower_bound(Begin, End, L-d);
    it != (Begin+(End-Begin)/2); ++it)
    {
        for(Point *j = (Begin+(End-Begin)/2), *jEnd = lower_bound(Begin, End, L+d);
        j != jEnd; j++)
        {
            if(checkInRange(*it, *j, d))
            {
                closest = min(closest, dis(*it, *j));
            }
        }
    }
    return closest;
}
int main()
{
    int pointN;
    Point arr[10005];
    while(cin >> pointN && pointN)
    {
        int arri = 0;
        for(int i = 0; i < pointN; i++)
        {
            double a, b;
            scanf("%lf%lf", &a, &b);
            arr[arri++] = Point(a, b);
        }
        sort(arr, arr+arri);
        double ans = ClosestPair(arr, arr+arri);
        if(ans < 10000.0)
            printf("%.4lf\n",ans);
        else
            puts("INFINITY");
    }
    return 0;
}

2016年10月4日 星期二

[UVA] 11624 - Fire!

題目連結

作法:
做BFS,紀錄每個點火與人分別要走幾步才能到達該點,
若火走 3 步到(i, j),人需走4步才到(i, j),
則該點人不能走,也就是不能加進BFS的queue。

須注意的點是:
1.人與火分開做BFS,即火全部BFS完後,再對人做BFS。
  在另一篇前輩的文章說,同時做BFS會讓記憶體跳來跳去,可能造成TLE。
2.火不一定會擴散到整張地圖,
例如:
3 3
J..
###
F..

該點若火沒擴散到,人是可以走的(可以加進人的BFS qeuue中)。

**************************************************
程式碼:

/* 題目: UVa 11624 - Fire!
 * Language: C++
 * Created on: 2016年10月05日
 *   Author: hanting
 */
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
struct Coor
{
    int i, j;
    Coor(int a = 0, int b = 0)
    {
        i = a;
        j = b;
    }
};
int main()
{
    int testCase;
    cin >> testCase;
    while(testCase--)
    {
        int r, c;
        cin >> r >> c;
        cin.get();
        vector<vector<char> > vec(r+2, vector<char>(c+2, 0));
        vector<vector<int> > fire(r+2, vector<int>(c+2, -1));
        vector<vector<int> > joe(r+2, vector<int>(c+2, -1));
        queue<Coor> J, F;
        for(int i = 1; i <= r; i++)
        {
            for(int j = 1; j <= c; j++)
            {
                cin >> vec[i][j];
                if(vec[i][j] == 'J')
                {
                    joe[i][j] = 0;
                    J.push(Coor(i, j));
                }
                else if (vec[i][j] == 'F')
                {
                    fire[i][j] = 0;
                    F.push(Coor(i, j));
                }
            }
        }
        Coor pos[4] = {{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
        bool escape = false;
        int cnt = 0;
        while(F.size())
        {
            Coor tmp = F.front();
            F.pop();
            int num = fire[tmp.i][tmp.j];
            for(int i = 0; i < 4; i++)
            {
                int x, y;
                x = tmp.i+pos[i].i;
                y = tmp.j+pos[i].j;

                if(fire[x][y]!=-1) continue;
                if(vec[x][y] == '.'|| vec[x][y] == 'J')
                {
                    F.push(Coor(x, y));
                    fire[x][y] = num+1;
                }
            }
        }
        while(J.size() && !escape)
        {
            Coor tmp = J.front();
            J.pop();
            int num = joe[tmp.i][tmp.j];
            for(int i = 0; i < 4; i++)
            {
                int x, y;
                x = tmp.i+pos[i].i;
                y = tmp.j+pos[i].j;
                if(vec[x][y] == 0)
                {
                    escape = true;
                    cnt = num+1;
                    break;
                }
                if(joe[x][y]!=-1) continue;
                if(vec[x][y] == '.' && (fire[x][y] == -1 || fire[x][y] > num+1))
                {
                    J.push(Coor(x, y));
                    joe[x][y] = num+1;
                }
            }
        }
        if(escape)
        {
            cout << cnt << endl;
        }
        else
        {
            cout << "IMPOSSIBLE" << endl;
        }
    }

    return 0;
}

2016年10月2日 星期日

[UVA] 10181 - 15-Puzzle Problem

題目連結
TLE 幾百次後 才發現原因在 board[0][k] 居然不等於 board[k/4][k%4],
改一下就AC了...害我一直對ida*優化到0秒

/* 題目: UVa 10181 - 15-Puzzle Problem
 * Language: C++
 * Created on: 2016年10月02日
 *   Author: hanting
 */
#include <iostream>
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
using namespace std;
int board[4][4];
int table[16][2];
inline bool canSolve(int x)
{
    int result = 0;
    for(int i = 0; i < 16; i++)
    {
        for(int j = i+1; j < 16; j++)
        {
            if(board[j/4][j%4] and board[i/4][i%4] and board[j/4][j%4] < board[i/4][i%4]) result++;
        }
    }
    return (result+x)&1;
}
inline int getStatus()
{
    int cnt = 0;
    for(int i = 0; i < 4; i++)
    {
        for(int j = 0; j < 4; j++)
        {
            if(board[i][j]) cnt += abs(table[board[i][j]][0] - i) + abs(table[board[i][j]][1] - j);
        }
    }
    return cnt;
}
char ansStk[100];
char stk[100];
int stki;
enum
{
    UP, DOWN, LEFT, RIGHT
};
int maxd;
int tmpMaxd;
int Htable[4][4][16]; // Htable[i][j][num] // num在[i][j]的cost
bool no;
bool dfs(int depth, int i, int j, int prePos, int status)
{
    if(depth > 50)
    {
        no = true;
        return false;
    }
    if(depth + status*4/3 > maxd)
    {
        tmpMaxd = min(tmpMaxd, depth + status*4/3);
        if(depth == 0) maxd = tmpMaxd;
        return false;
    }
    if(status == 0)
    {
        stk[stki] = 0;
        cout << stk;
        return true;
    }

    if(prePos != UP and i+1 < 4)
    {
        swap(board[i][j], board[i+1][j]);
        stk[stki++] = 'D';
        int nextStatus = status;
       nextStatus -= Htable[i+1][j][board[i][j]];
       nextStatus += Htable[i][j][board[i][j]];
        if(dfs(depth+1 , i+1, j, DOWN, nextStatus) ) return true;
        stki--;
        swap(board[i][j], board[i+1][j]);
    }
    if(prePos != LEFT and j+1 < 4)
    {
        swap(board[i][j], board[i][j+1]);
        stk[stki++] = 'R';
        int nextStatus = status;
        nextStatus -= Htable[i][j+1][board[i][j]];
        nextStatus += Htable[i][j][board[i][j]];
        if(dfs(depth+1 , i, j+1, RIGHT, nextStatus) ) return true;
        stki--;
        swap(board[i][j], board[i][j+1]);
    }

    if(prePos != DOWN and i-1 >= 0)
    {
        swap(board[i][j], board[i-1][j]);
        stk[stki++] = 'U';
        int nextStatus = status;
        nextStatus -= Htable[i-1][j][board[i][j]];
        nextStatus += Htable[i][j][board[i][j]];
        if(dfs(depth+1,  i-1, j, UP, nextStatus) ) return true;
        stki--;
        swap(board[i][j], board[i-1][j]);
    }

    if(prePos != RIGHT and j-1 >= 0)
    {
        swap(board[i][j], board[i][j-1]);
        stk[stki++] = 'L';
        int nextStatus = status;
        nextStatus -= Htable[i][j-1][board[i][j]];
        nextStatus += Htable[i][j][board[i][j]];
        if(dfs(depth+1 , i, j-1, LEFT, nextStatus) ) return true;
        stki--;
        swap(board[i][j], board[i][j-1]);
    }
    maxd = tmpMaxd;
    return false;
}
int main()
{
    for(int i = 1; i < 16; i++)
    {
        table[i][0] = (i-1) / 4;
        table[i][1] = (i-1) % 4 ;
    }
    for(int i = 0; i < 4; i++)
    {
        for(int j = 0; j < 4; j++)
        {
            for(int k = 1; k < 16; k++)
            {
                Htable[i][j][k] = abs(table[k][0] - i) + abs(table[k][1] -j);
            }
        }
    }
    int n;
    cin >> n;
    while(n--)
    {
        int x0, y0;
        memset(ansStk, 0, sizeof(ansStk));
       int ti = 0;
        for(int i = 0; i < 4; i++)
        {
            for(int j = 0; j < 4; j++)
            {
                cin >> board[i][j];
                if(board[i][j] == 0)
                {
                    x0 = i;
                    y0 = j;
                }
            }
        }
        if(!canSolve(x0))
        {
            cout << "This puzzle is not solvable." << endl;
            continue;
        }
        int status = getStatus();
        maxd = status;
        no = false;
        for(;;)
        {
        tmpMaxd = 0x3fffffff;
        stki = 0;;
            if(dfs(0, x0, y0, -1, status))
            {
                break;
            }
            if(no)
            {
                cout << "This puzzle is not solvable." ;
                break;
            }
        }
        cout << endl;
    }

    return 0;
}

2016年7月12日 星期二

[UVA] 10428 - The Roots

題目連結
這題ac uva rank 1耶真是感動到快暴動了





程式碼:
/* 題目: UVa 10428 - The Roots
 * Language: C++
 * Created on: 2016年7月12日
 *   Author: hanting
 */
#include <iostream>
#include <cstring> // memset
#include <iomanip> // setprecision
#include <cmath> // fabs
#include <algorithm> // sort
#include <vector>
#include <cstdio>
using namespace std;
double a[6];
double f(double x) // 高效率求一元多次多項式的值
{
    double result = a[5];
    for(int i = 4; i >= 0; i--)
    {
        result = result * x + a[i];
    }
    return result;
}
double f1(double x)
{
    double result = a[5]*5;
    for(int i = 4; i > 0; i--)
    {
        result = result * x + a[i]*i;
    }
    return result;
}
double newtonsMethod(double x0)
{
    double x1 = x0;
    int cnt = 0;
    do
    {
        if(++cnt == 100) break;
        x0 = x1;
        if(fabs(f(x0)) < 1e-10) return x0;
        x1 = x0 - f(x0)/f1(x0);
    }
    while(fabs(x1 - x0) > 1e-10);
    return x1;
}
void PolynomialDivision(double b, double c) // f div (bx+c)
{
    for(int i = 5; i > 0; i--)
    {
        a[i-1] -= a[i] / b * c;
        a[i] /= b;
    }
    for(int i = 0; i < 5; i++)
    {
        a[i] = a[i+1];
    }
    a[5] = 0;
}
void findRoot(vector<double> &root, int N)
{
    double oneRoot;
    while(root.size() < N)
    {
        oneRoot = newtonsMethod(0);
        root.push_back(oneRoot);
        PolynomialDivision(1, -oneRoot);
    }
}
int main()
{
    int N;
    int caseN = 1;
    while(/*cin >> N*/scanf("%d", &N) == 1 and N)
    {
        memset(a, 0, sizeof(a));
        for(int i = N; i >= 0; i--)
        {
            //cin >> a[i];
            scanf("%lf", a+i);
        }
        vector<double> root;
        findRoot(root, N);
        sort(root.begin(), root.end());
        printf("Equation %d:", caseN++);
        //cout << "Equation " << caseN++ << ":" ;
        for(int i = 0; i < N; i++)
        {
            printf(" %.4lf", root[i]);
            //cout << " " << fixed << setprecision(4) << root[i];
        }
        printf("\n");
        //cout << endl;
    }
    return 0;
}

2016年7月9日 星期六

[UVA] 684 - Integral Determinant

題目連結

程式碼:
/* 題目: UVa 684 -  Integral Determinant
 * Language: C++
 * Created on: 2016年7月10日
 *   Author: hanting
 */
#include <iostream>
#include <vector>
using namespace std;
long long gcd(long long a1, long long b1)
{
    unsigned long long a, b;
    if(a1 < 0) a1 *= -1;
    if(b1 < 0) b1 *= -1;
    a = a1;
    b = b1;
    while(a and b)
    {
        (a > b) ? (a %= b) : (b %= a);
    }
    return a ? a : b;
}
long long lcm(long long a, long long b)
{
    return a / gcd(a, b) * b; // a要先/gcd
}
struct Real
{
    long long mom, son;
    Real(int s = 0, int m = 1):mom(m), son(s) {}
    void simple()
    {
        if(mom < 0)
        {
            son *= -1;
            mom *= -1;
        }
        long long _gcd = gcd(mom, son);
        mom /= _gcd;
        son /= _gcd;
    }
    Real operator * (Real b)
    {
        Real result = *this;
        long long gcd1, gcd2;
        gcd1 = gcd(result.mom, b.son);
        gcd2 = gcd(result.son, b.mom);
        result.mom /= gcd1;
        b.son /= gcd1;
        result.son /= gcd2;
        b.mom /= gcd2;
        result.mom *= b.mom;
        result.son *= b.son;
        result.simple();
        return result;
    }
    Real operator / (Real b)
    {
        Real result = *this;
        long long gcd1, gcd2;
        gcd1 = gcd(result.mom, b.mom);
        gcd2 = gcd(result.son, b.son);
        result.mom /= gcd1;
        b.mom /= gcd1;
        result.son /= gcd2;
        b.son /= gcd2;
        result.mom *= b.son;
        result.son *= b.mom;
        result.simple();
        return result;
    }
    void operator -=(Real b)
    {
        long long lcm1 = lcm(mom, b.mom);
        long long a1, b1;
        a1 = lcm1 / mom;
        b1 = lcm1 / b.mom;
        son = son*a1 - b.son*b1;
        mom = lcm1;
        simple();
    }
    void operator *= (Real b)
    {
        long long gcdMom, gcdSon;
        gcdMom = gcd(mom, b.son);
        gcdSon = gcd(son, b.mom);
        mom /= gcdMom;
        b.son /= gcdMom;
        son /= gcdSon;
        b.mom /= gcdSon;

        mom *= b.mom;
        son *= b.son;
        simple();
    }
    void operator /= (Real b)
    {
        long long gcd1, gcd2;
        gcd1 = gcd(mom, b.mom);
        gcd2 = gcd(son, b.son);
        mom /= gcd1;
        b.mom /= gcd1;
        son /= gcd2;
        b.son /= gcd2;
        mom *= b.son;
        son *= b.mom;
        simple();
    }
    friend istream& operator >> (istream &in, Real &r)
    {
        in >> r.son;
        r.mom = 1;
        return in;
    }
    friend ostream& operator << (ostream &out, Real r)
    {
        out << r.son;
        if(r.mom != 1 and r.son) out << '/' << r.mom;
        return out;
    }
};
void doDownTriangle(vector<vector<Real> > &vec) // 讓矩陣對角線以下全變為0
{
    for(int k = 0; k < vec.size(); k++)
    {
        int index = k; // find first element not zero
        while(index < vec.size() and vec[index][k].son == 0) index++;
        if(index == vec.size())
        {
            vec[0][0] = 0;
            return ;
        }
        if(index != k)
        {
            swap(vec[index], vec[k]);
            for(int i = k; i < vec.size(); i++)
            {
                vec[k][i].son *= -1;
            }
        }
        Real tmp = vec[k][k];
        for(int i = k+1; i < vec.size(); i++)
        {
            Real r = vec[i][k] / tmp;
            for(int j = k; j < vec[i].size(); j++)
            {
                vec[i][j] -= vec[k][j] * r;
            }
        }
    }
}
Real Determinant(vector<vector<Real> > &vec)
{
    doDownTriangle(vec);
    Real result(1);
    for(int i = 0; i < vec.size(); i++)
    {
        result *= vec[i][i]; // 因下三角全為0,故對角線乘積為答案
    }
    return result;
}
int main()
{
    int n;
    while(cin >> n and n)
    {
        vector<vector<Real> > matrix(n, vector<Real>(n));
        for(int i = 0; i < n; i++)
        {
            for(int j = 0; j < n; j++)
                cin >> matrix[i][j];
        }
        cout <<Determinant(matrix) << endl;
    }
    cout << "*" << endl;
    return 0;
}

2016年5月22日 星期日

[UVA] 11995 - I Can Guess the Data Structure!

/* 題目: UVa 11995 - I Can Guess the Data Structure!
 * Language: C++
 * Created on: 2016年5月22日
 *   Author: hanting
 */
#include <iostream>
#include <stack>
#include <queue>
using namespace std;
int main()
{
    int N;
    while(cin >> N)
    {
        bool test[3] = {};
        queue<int> que;
        priority_queue<int> pque;
        stack<int> stk;
        int op;
        int num;
        for(int i = 0; i < N; i++)
        {
            cin >> op >> num;
            if(op == 1)
            {
                que.push(num);
                pque.push(num);
                stk.push(num);
            }
            else //if(op == 2)
            {
                int tmp;
                if(test[0] == 0)
                {
                    if(que.size())
                    {
                        tmp = que.front();
                        if(tmp != num)
                        {
                            test[0] = 1;
                        }
                        else
                        {
                            que.pop();
                        }
                    }
                    else
                    {
                        test[0] = 1;
                    }
                }
                if(test[1] == 0)
                {
                    if(pque.size())
                    {
                        tmp = pque.top();
                        if(tmp != num)
                        {
                            test[1] = 1;
                        }
                        else
                        {
                            pque.pop();
                        }
                    }
                    else
                    {
                        test[1] = 1;
                    }
                }
                if(test[2] == 0)
                {
                    if(stk.size())
                    {
                        tmp = stk.top();
                        if(tmp != num)
                        {
                            test[2] = 1;
                        }
                        else
                        {
                            stk.pop();
                        }
                    }
                    else
                    {
                        test[2] = 1;
                    }
                }
            }
        }
        int cnt = 0;
        for(int i = 0; i < 3; i++)
        {
            if(test[i] == 0) cnt++;
        }
        if(cnt == 0)
        {
            cout << "impossible" << endl;
        }
        else if(cnt == 1)
        {
            if(test[0] == 0)
            {
                cout << "queue" << endl;
            }
            else if(test[1] == 0)
            {
                cout << "priority queue" << endl;
            }
            else
            {
                cout << "stack" << endl;
            }
        }
        else
        {
            cout << "not sure" << endl;
        }
    }

    return 0;
}

2016年5月7日 星期六

[UVA] 11195 - Another n-Queen Problem

題目連結



==================================================
程式碼:
/* 題目: UVa 11195 - Another n-Queen Problem
 * Language: C++
 * Created on: 2016年05月08日
 *   Author: hanting
 */
#include <iostream>
#include <vector>
#include <string>
#include <bitset>
using namespace std;
#pragma warning(disable:4996)
int ans;
vector<int > arr;
vector<string> vec;
void DFS(int row, int ld, int rd, int N, int cnt)
{
if (cnt == N)
{
ans++;
return;
}
int next = row | ld | rd;
for (int i = 0; i < N; i++)
{
int mask = 1 << i;
if (!(next & mask) && vec[cnt][i] != '*')
{
DFS(row|mask, (ld|mask) << 1, (rd|mask) >> 1, N, cnt + 1);
}
}
}
int main()
{
int N;
int CaseN = 1;
while (cin >> N && N)
{
ans = 0;
arr.assign(N, 0);
vec.assign(N, "");
for (int i = 0; i < N; i++)
{
cin >> vec[i];
}
DFS(arr[0], 0, 0, N, 0);
cout << "Case " << CaseN++ << ": " << ans << endl;
}
}

2016年5月1日 星期日

[UVA] 11956 - Brainfuck

/* 題目: UVa 11956 - Brainfuck
 * Language: C++
 * Created on: 2016年05月01日
 *   Author: hanting
 */
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
    int CaseN = 1;
    int testCase = 0;
    cin >> testCase;
    cin.get();
    while(testCase--)
    {
        cout << dec << "Case " << CaseN++ << ":";
        string ins;
        getline(cin, ins);
        unsigned char memory[100] = {};
        int ptr = 0;
        for(int i = 0; i < ins.size(); i++)
        {
            if(ins[i] == '+') memory[ptr]++;
            else if(ins[i] == '-') memory[ptr]--;
            else if(ins[i] == '>') ptr++;
            else if(ins[i] == '<') ptr--;
            if(ptr < 0) ptr = 99;
            else if(ptr > 99) ptr = 0;
        }
        for(int i = 0; i < 100; i++)
        {
            cout << " ";
            cout << setw(2);
            cout << uppercase << setfill('0') << hex << (int)memory[i];
        }
        cout << endl;
    }
    return 0;
}

2016年4月7日 星期四

[UVA] 112 - Tree Summing

/* 題目: UVa 112 - Tree Summing
 * Language: C++
 * Created on: 2016年4月7日
 *   Author: hanting
 */
#include <iostream>
#include <cstring> // memset
#include <sstream>
using namespace std;
const int maxN = 100000;
int arr[maxN];
bool arr2[maxN];
string tree;
stringstream sin;
bool check;
void buildTree(int ptr)
{
    if(ptr < maxN)
    {
        char ch;
        sin >> ch;
        sin >> ch;
        if(ch == '*')
        {
            int num;
            sin >> num;
            arr[ptr] = num;
            arr2[ptr] = true;
            buildTree(ptr*2);
            buildTree(ptr*2+1);
            sin >> ch;
        }
        /*else if(ch == ')')
        {

        }*/
    }
}
void init()
{
    memset(arr, 0, sizeof(arr));
    memset(arr2, 0, sizeof(arr2));
    tree.clear();
    check = false;
    int flag = 0;
    char c;
    char last;
    while(c = cin.get())
    {
        if(tree.size()) last = tree[tree.size()-1];
        if(c == ' ' or c == '\n') continue;
        if(c == '(') flag++;
        else if(c == ')') flag--;
        else if(isdigit(c) and (last != '-' and !isdigit(last)))
        {
            tree += '*';
        }
        else if(c == '-')
        {
            tree += '*';
        }
        if(flag >= 0) tree += c;
        if(flag == 0) break;
    }
    sin.clear();
    sin.str(tree);
}
void DFS(int index, int n)
{
    if(index < maxN and arr2[index])
    {
        n -= arr[index];
        if(!arr2[index*2] and !arr2[index*2+1] and n == 0)
        {
            check = true;
            return ;
        }
        DFS(index*2, n);
        DFS(index*2+1, n);
    }
}
int main()
{
    int n;
    int i = 1;
    while(cin >> n)
    {
        init();
        buildTree(1);
        if(arr2[1])DFS(1, n);
        cout << (check ? "yes\n":"no\n");
    }
    return 0;
}

2016年3月26日 星期六

[UVA] 297 - Quadtrees

/* 題目: UVa 297 - Quadtrees
 * Language: C++
 * Created on: 2016年3月26日
 *   Author: hanting
 */
#include <iostream>
using namespace std;
int stri = 1;
void build(bool *table, string str, int index)
{
    if(stri < str.size())
    {
        for(int i = 1; i <= 4; i++)
        {
            if(str[stri] == 'p')
            {
                stri++;
                table[index+i] = 0;
                build(table, str, 4*(index+i));
            }
            else if(str[stri] == 'e')
            {
                stri++;
                table[index+i] = 0;
            }
            else // if(str[stri] == 'f')
            {
                stri++;
                table[index+i] = 1;
            }
        }
    }

}
int value(bool *table, int index)
{
    if(index < 2048)
    {
        if(table[index])
        {
            if(index == 0) return 1024;
            else if(index <= 4) return 256;
            else if(index <= 20) return 64;
            else if(index <= 84) return 16;
            else if(index <= 340) return 4;
            else return 1;
        }
        else
        {
            int subIndex = index*4;
            int sum = 0;
            for(int i = 1; i <= 4; i++)
            {
                sum += value(table, subIndex+i);
            }
            return sum;
        }
    }
    return 0;
}
int main()
{
    int testCase = 0;
    cin >> testCase;
    while(testCase--)
    {
        stri = 1;
        bool table1[2048] = {0};
        bool table2[2048] = {0};

        string str1, str2;
        cin >> str1 >> str2;
        if(str1[0] == 'p')
            build(table1, str1, 0);
        else
            table1[0] = str1[0] == 'f';

        stri = 1;
        if(str2[0] == 'p')
            build(table2, str2, 0);
        else
            table2[0] = str2[0] == 'f';

        for(int i = 0; i < 2048; i++)
        {
            table1[i] = table1[i] or  table2[i];
        }
        cout << "There are " << value(table1, 0) << " black pixels." << endl;
    }

    return 0;
}