neoj 461

演算法邏輯如下
對所有的霸霸、咩咩、喵喵
計算他們與娃娃魚的距離
只要至少一個霸霸且至少一個咩咩且至少一個喵喵

與娃娃魚的距離小於要求 (10, 10, 12)

就可以輸出解

distance function

作法一

直接計算
sqrt() (#include <cmath>就有)

double distance(int x1, int y1, int x2, int y2){
    int sqrx = (x1 - x2) * (x1 - x2);
    int sqry = (y1 - y2) * (y1 - y2);
    return sqrt(sqrx + sqry);
}

distance function

作法二

為了避免浮點數誤差

改成透過 dis * dis 來比較距離
數學上等價 

int distance(int x1, int y1, int x2, int y2){
    int sqrx = (x1 - x2) * (x1 - x2);
    int sqry = (y1 - y2) * (y1 - y2);
    return sqrx + sqry;
}

distance function

long long distance(int x1, int y1, int x2, int y2){
	long long lx1, ly1, lx2, ly2;
	lx1 = x1, ly1 = y1, lx2 = x2, ly2 = y2;
    long long sqrx = (lx1 - lx2) * (lx1 - lx2);
    long long sqry = (ly1 - ly2) * (ly1 - ly2);
	
    return sqrx + sqry;
}
/*
	int a, b;	 
	long long c = a * b; //這樣還是會overlflow哦 因為a*b的時候就已經超過了,詳情請見轉型一章
*/

順帶一提,本題的測資很友善,都不會超過int的範圍

日後實作需要int * int的問題的時候都要注意是否會在運算中 overflow

必要時候請使用 long long

distance function

long long distance(int x1, int y1, int x2, int y2){
    long long sqrx = (1LL * x1 - y2) * (lx1 - lx2);
    long long sqry = (1LL * y1 - y2) * (ly1 - ly2);
    return sqrx + sqry;
}

小小訣竅

isValid function

bool isValid(int a, int b, int c,
	int baba[], int meme[], int meow[],
	int x, int y){
    bool getbaba, getmeme, getmeow;
    getbaba = getmeme = getmeow = false;
    for(int i = 0; i < a; i++) {
        double disbaba = distance(x, y, baba[i * 2], baba[i * 2 + 1]);
        if (disbaba <= 10.0) {
            getbaba = true;
            break;
        }
    }
 	/* ... */
    if(getmeow && getmeme && getbaba)
        return true;
    return false;
}

這邊只示範 霸霸

isValid function

for(int i = 0; i < a; i++) {
    double disbaba = 
    distance(x, y, baba[i * 2], baba[i * 2 + 1]);
    if (disbaba <= 10.0) {
        getbaba = true;
        break;
    }
}

重點部分

isValid function

const double eps = 1e-8;
int dcmp(double a, double b){
	if(fabs(a - b) <= eps)
    	return 0;
    if(a - b > 0) return 1;
    else return -1;
}
for(int i = 0; i < a; i++) {
    double disbaba = 
    distance(x, y, baba[i * 2], baba[i * 2 + 1]);
    if (dcmp(disbaba,10.0) <= 0) {
        getbaba = true;
        break;
    }
}

浮點數比較建議作法 (有點進階)

isValid function

int distance(int x1, int y1, int x2, int y2){
    int sqrx = (x1 - x2) * (x1 - x2);
    int sqry = (y1 - y2) * (y1 - y2);
    return sqrx + sqry;
}
for(int i = 0; i < a; i++) {
    int disbaba = 
    distance(x, y, baba[i * 2], baba[i * 2 + 1]);
    if (disbaba <= 10*10) {
        getbaba = true;
        break;
    }
}

如果我們用剛剛的distance 作法二,只比較dis * dis 一定沒問題

neoj 4328

Thinking

path 0 1 2 ​3 4 5 6 7 8
1 4 0 7 8 6 3 5 2
path 0 1 2 ​3 4 5 6 7 8
1 4 0 7 8 6 3 5 2

Thinking

path 0 1 2 ​3 4 5 6 7 8
1 4 0 7 8 6 3 5 2
path 0 1 2 ​3 4 5 6 7 8
1 4 0 7 8 6 3 5 2

Thinking

path 0 1 2 ​3 4 5 6 7 8
1 4 0 7 8 6 3 5 2
path 0 1 2 ​3 4 5 6 7 8
1 4 0 7 8 6 3 5 2

解法

int visited[100000] : visited[i] 紀錄走到第 i 位置的人,若從沒被走到過則設為 -1。
int path [n] : 如題目定義,魔法陣列。

int pos : 如題目定義,紀錄每個人當前回合的位置。 

  1. 模擬每回合,一回合移動每個人
  2. 一個人在移動之後,先檢查新位置有沒有被別人踩過,而且不是自己。
    1. 如果被別人踩過,return 當前回合數 
    2. 如果沒有,將visited設成自己

解法

int walkOnMyOwnPath(int path[], int pos[], int size, int time){
	/* 初始化自己來,小心有沒有人一開始就踩在同個位置上 */
	/* visited[i] 初始化為全部都為 -1*/
	/* 一開始所有人站的位置,visited[pos[j]]都要設成站在那個位置上的人的index*/
	int t = 0;
    while(t <= time) {
        t++;
        for (int j = 0; j < size; j++) {
            pos[j] = path[ pos[j] ];
            if (visited[pos[j]] != j) {
                if(visited[pos[j]] != -1)
                    return t;
                else{
                    visited[pos[j]] = j;
                }
            }
        }
    }
    return -1;
}

解法

時間複雜度 ? 

while(t <= time) {
   t++;
   for (int j = 0; j < size; j++) {
       pos[j] = path[ pos[j] ];
       if (visited[pos[j]] != j) {
           if(visited[pos[j]] != -1)
                return t;
           else{
                visited[pos[j]] = j;
           }
       }
    }
}
O(10^5 \times 10) \text{?}

如果有人會踩到

一定在100000回合內踩到

解法

時間複雜度 ? 

int t = 0;
while(t <= time) {
   t++;
   for (int j = 0; j < size; j++) {
       pos[j] = path[ pos[j] ];
       if (visited[pos[j]] != j) {
           if(visited[pos[j]] != -1)
                return t;
           else{
                visited[pos[j]] = j;
           }
       }
    }
}
O(10^9 \times 10) \text{?}

要是一直循環??

解法

時間複雜度 ?  修正 ? 

bool circle = false;
int t = 0;
while(!circle && t <= time) {
    t++;
    circle = true;
    for (int j = 0; j < size; j++) {
        pos[j] = path[ pos[j] ];
        if (visited[pos[j]] != j) {
            if(visited[pos[j]] != -1)
                return t;
            else{
                visited[pos[j]] = j;
                circle = false;
            }
        }
    }
}
O(10^5 \times 10) \text{?}

判斷出現了cycle !?!?!?!?

Made with Slides.com