2022年2月6日 星期日

d406: 倒水時間

解題心得

在dfs的「探索相鄰節點」步驟除了一一列舉外,還有更簡潔的寫法,就是將座標所需的位移裂成矩陣,迴圈檢查合法與否即可。

程式碼

#include <iostream>
#include <queue>
using namespace std;

int map[101][101] = { 0 };
struct Point
{
	int x, y, step = -1;
};

int main()
{
	int s, n, m, counter = 1;
	while (cin >> s)
	{
		cin >> n >> m;
		bool isVisited[101][101] = { false };
		Point start, now;
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < m; j++)
			{
				cin >> map[i][j];
				if (i == 0 && map[i][j] == 1)
					start.x = i, start.y = j;
			}
		}
		queue<Point> q;
		isVisited[start.x][start.y] = true;
		start.step = 1;
		q.push(start);
		int dx[4] = { 1,0,0,-1 }, dy[4] = { 0,1,-1,0 }; // 最後一個是往上
		while (!q.empty())
		{
			now = q.front(); q.pop();
			for (int i = 0; i < 4; i++)
			{
				if (i == 3 && s == 2) break;
				Point p;
				p.x = now.x + dx[i]; p.y = now.y + dy[i];
				if (p.x >= 0 && p.x < n && p.y >= 0 && p.y < m && map[p.x][p.y] != 0 && !isVisited[p.x][p.y])
				{
					isVisited[p.x][p.y] = true;
					p.step = now.step + 1;
					map[p.x][p.y] = p.step;
					q.push(p);
				}
				
			}
			isVisited[now.x][now.y] = true;
		}
		cout << "Case " << counter++ << ":" << endl;
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < m; j++)
			{
				if (map[i][j] != 0 && !isVisited[i][j]) cout << 0;
				else cout << map[i][j];
				if (j != m - 1) cout << " ";
				else cout << endl;
			}
		}
	}
	return 0;
}

2022年2月4日 星期五

c124: 00532 - Dungeon Master

解題心得

除了東西南北外,多考慮上下的bfs。

程式碼

#include <iostream>
#include <queue>
using namespace std;

struct Point
{
	int level, x, y, step = -1;
};
int l, r, c;
char map[31][31][31];


int main()
{
	
	while (cin >> l >> r >> c)
	{
		if (l == 0 && r == 0 && c == 0) break;

		bool isVisit[31][31][31] = { false };
		Point start, end, now;
		for (int i = 0; i < l; i++)
		{
			for (int j = 0; j < r; j++)
			{
				for (int k = 0; k < c; k++)
				{
					cin >> map[i][j][k];
					if (map[i][j][k] == 'S')
						start.level = i, start.x = j, start.y = k;
					if (map[i][j][k] == 'E')
						end.level = i, end.x = j, end.y = k;
				}
			}
			cin.ignore();
		}
		
		queue<Point> q;
		start.step = 0;
		q.push(start);
		isVisit[start.level][start.x][start.y] = true;
		bool isValid = false;
		while (!q.empty())
		{
			now = q.front(); q.pop();
			//cout << now.level << " " << now.x << " " << now.y << " " << now.step << endl;
			if (map[now.level][now.x][now.y] == 'E')
			{
				cout << "Escaped in " << now.step << " minute(s)." << endl;
				isValid = true;
				break;
			}
			if (now.x - 1 >= 0 && map[now.level][now.x - 1][now.y] != '#' && !isVisit[now.level][now.x - 1][now.y])
			{
				isVisit[now.level][now.x - 1][now.y] = true;
				Point p; p.level = now.level; p.x = now.x - 1; p.y = now.y;
				p.step = now.step + 1;
				q.push(p);
			}
			if (now.x + 1 < r && map[now.level][now.x + 1][now.y] != '#' && !isVisit[now.level][now.x + 1][now.y])
			{
				isVisit[now.level][now.x + 1][now.y] = true;
				Point p; p.level = now.level; p.x = now.x + 1; p.y = now.y;
				p.step = now.step + 1;
				q.push(p);
			}
			if (now.y - 1 >= 0 && map[now.level][now.x][now.y - 1] != '#' && !isVisit[now.level][now.x][now.y - 1])
			{
				isVisit[now.level][now.x][now.y - 1] = true;
				Point p; p.level = now.level; p.x = now.x; p.y = now.y - 1;
				p.step = now.step + 1;
				q.push(p);
			}
			if (now.y + 1 < c && map[now.level][now.x][now.y + 1] != '#' && !isVisit[now.level][now.x][now.y + 1])
			{
				isVisit[now.level][now.x][now.y + 1] = true;
				Point p; p.level = now.level; p.x = now.x; p.y = now.y + 1;
				p.step = now.step + 1;
				q.push(p);
			}
			if (now.level - 1 >= 0 && map[now.level - 1][now.x][now.y] != '#' && !isVisit[now.level - 1][now.x][now.y])
			{
				isVisit[now.level- 1][now.x][now.y ] = true;
				Point p; p.level = now.level - 1; p.x = now.x; p.y = now.y;
				p.step = now.step + 1;
				q.push(p);
			}
			if (now.level + 1 < l && map[now.level + 1][now.x][now.y] != '#' && !isVisit[now.level + 1][now.x][now.y])
			{
				isVisit[now.level + 1][now.x][now.y] = true;
				Point p; p.level = now.level + 1; p.x = now.x; p.y = now.y;
				p.step = now.step + 1;
				q.push(p);
			}
			isVisit[now.level][now.x][now.y] = true;
		}
		if (!isValid) cout << "Trapped!" << endl;
	}
	return 0;
}

d453: 三、最短距離

解題心得

也是中規中矩的bfs(?

記得清空,以及題目input的座標是從1開始。

程式碼

#include <iostream>
#include <queue>
using namespace std;

struct Point
{
	int x, y, step = -1;
};
char map[101][101] = { 0 };
bool isVisited[101][101] = { false };
int main()
{
	int N, n, m;
	Point start, end, now;
	cin >> N;
	while (N--)
	{
		cin >> n >> m >> start.x >> start.y >> end.x >> end.y;
		for (int i = 0; i < n; i++)
			for (int j = 0; j < m; j++)
				cin >> map[i][j];
		for (int i = 0; i < n; i++)
			for (int j = 0; j < m; j++)
				isVisited[i][j] = false;
		start.x -= 1; start.y -= 1; end.x -= 1; end.y -= 1;
		//bfs
		queue<Point> q;
		isVisited[start.x][start.y] = true; start.step = 1;
		bool isValid = false;
		q.push(start);
		while (!q.empty())
		{
			now = q.front(); 
			q.pop();
			//cout << now.x << " " << now.y << " " << now.step << endl;
			if (now.x == end.x && now.y == end.y)
			{
				cout << now.step << endl;
				isValid = true;
				break;
			}
			if (now.x - 1 >= 0 && map[now.x - 1][now.y] == '0' && !isVisited[now.x - 1][now.y])
			{
				Point p; p.x = now.x - 1; p.y = now.y; 
				isVisited[now.x - 1][now.y] = true;
				p.step = now.step + 1;
				q.push(p);
			}
			if (now.x + 1 < n && map[now.x + 1][now.y] == '0' && !isVisited[now.x + 1][now.y])
			{
				Point p; p.x = now.x + 1; p.y = now.y;
				isVisited[now.x + 1][now.y] = true;
				p.step = now.step + 1;
				q.push(p);
			}
			if (now.y - 1 >= 0 && map[now.x][now.y - 1] == '0' && !isVisited[now.x][now.y - 1])
			{
				Point p; p.x = now.x; p.y = now.y - 1;
				isVisited[now.x][now.y - 1] = true;
				p.step = now.step + 1;
				q.push(p);
			}
			if (now.y + 1 < m && map[now.x][now.y + 1] == '0' && !isVisited[now.x][now.y + 1])
			{
				Point p; p.x = now.x; p.y = now.y + 1;
				isVisited[now.x][now.y + 1] = true;
				p.step = now.step + 1;
				q.push(p);
			}
			isVisited[now.x][now.y] = true;
		}
		if (!isValid) cout << 0 << endl;
	}
	return 0;
}

a290: 新手訓練系列 ~ 圖論

解題心得

中規中矩的題目,記得要清空graph再繼續吃新測資。

不過我是看以前上課講義的演算法寫的XD

程式碼

#include <iostream>
#include <queue>
using namespace std;

int graph[801][801] = { 0 };

int main()
{
	ios_base::sync_with_stdio(0);
	cin.tie(0);
	int n, m, a, b, now;
	while (cin >> n >> m)
	{
		for (int i = 0; i <= n; i++)
			for (int j = 0; j <= n; j++)
				graph[i][j] = 0;
		while (m--)
		{
			cin >> a >> b;
			graph[a][b] = 1;
		}
		cin >> a >> b;

		queue<int> q;
		bool isVisited[801] = { false }, isValid = false;
		q.push(a);
		isVisited[a] = true;
		while (!q.empty())
		{
			now = q.front();
			q.pop();
			for (int i = 1; i <= n; i++)
			{
				if (graph[now][i] == 1 && isVisited[i] == false)
				{
					isVisited[i] = true;
					q.push(i);

					if (i == b)
					{
						isValid = true;
						break;
					}
				}
			}
			isVisited[now] = true;
		}
		if (isValid) cout << "Yes!!!" << endl;
		else cout << "No!!!" << endl;
	}
	return 0;
}

d365: 10336 - Rank the Languages

解題心得

我反而不是卡bfs,而是卡再怎麼輸出好久,最開始是用map紀錄,但要依照value輸出好麻煩。

程式碼

#include <iostream>
#include <vector>
using namespace std;

int h, w;
void bfs(vector<vector<char>>& map, int x, int y, char c)
{
	map[y][x] = '@';
	if (x - 1 >= 0 && map[y][x - 1] == c) bfs(map, x - 1, y, c);
	if (x + 1 < w && map[y][x + 1] == c) bfs(map, x + 1, y, c);
	if (y - 1 >= 0 && map[y - 1][x] == c) bfs(map, x, y - 1, c);
	if (y + 1 < h && map[y + 1][x] == c) bfs(map, x, y + 1, c);
}


int main()
{
	int n;
	cin >> n;
	for (int round = 1; round <= n; round++)
	{
		cin >> h >> w;
		int dict[26] = { 0 };
		vector<vector<char>> map(h, vector<char>(w, '@'));
		for (int i = 0; i < h; i++)
		{
			for (int j = 0; j < w; j++)
				cin >> map[i][j];
		}
		for (int i = 0; i < h; i++)
		{
			for (int j = 0; j < w; j++)
			{
				if (map[i][j] != '@')
				{
					dict[map[i][j] - 'a']++;
					bfs(map, j, i, map[i][j]);
				}
			}
		}
		cout << "World #" << round << endl;
		int maxCount = 0;
		for (int i = 0; i < 26; i++)
			maxCount = max(maxCount, dict[i]);
		while (maxCount)
		{
			for (int i = 0; i < 26; i++)
			{
				if (maxCount == dict[i])
					cout << char('a' + i) << ": " << dict[i] << endl;
			}
			maxCount--;
		}
	}
	return 0;
}

2022年2月3日 星期四

Uva 10267: Graphical Editor

解題心得

看起來很麻煩,但基本上只要照著題目敘述做就好,最難的部分只有DFS。

程式碼

#include <iostream>
using namespace std;

char table[101][101];
int m, n;

void fill(int x, int y, char c, char currentColor)
{
	if(currentColor==c) return;
	table[y][x]=c;
	
	if(x>=2 && table[y][x-1]==currentColor) fill(x-1,y,c,currentColor);
	if(x<m && table[y][x+1]==currentColor) fill(x+1,y,c,currentColor);
	if(y>=2 && table[y-1][x]==currentColor) fill(x,y-1,c,currentColor);
	if(y<n && table[y+1][x]==currentColor) fill(x,y+1,c,currentColor);
}

int main()
{
	char cmd,c;
	int x1,x2,y1,y2;
	string name,s;
	while(cin>>cmd)
	{
		if(cmd=='I')
		{
			cin>>m>>n;
			for(int i=0;i<=n;i++)
				for(int j=0;j<=m;j++)
					table[i][j]='O';
		}
		else if(cmd=='L')
		{
			cin>>x1>>y1>>c;
			table[y1][x1]=c;
		}
		else if(cmd=='S')
		{
			cin>>name;
			cout<<name<<endl;
			for(int i=1;i<=n;i++)
			{
				for(int j=1;j<=m;j++)
					cout<<table[i][j];
				cout<<endl;
			}
					
		}
		else if(cmd=='F')
		{
			cin>>x1>>y1>>c;
			fill(x1,y1,c,table[y1][x1]);
		}
		else if(cmd=='V')
		{
			cin>>x1>>y1>>y2>>c;
			if(y1>y2) swap(y1,y2);
			for(int i=y1;i<=y2;i++)
				table[i][x1]=c;
		}
		else if(cmd=='H')
		{
			cin>>x1>>x2>>y1>>c;
			if(x1>x2) swap(x1,x2);
			for(int i=x1;i<=x2;i++)
				table[y1][i]=c;
		}
		else if(cmd=='K')
		{
			cin>>x1>>y1>>x2>>y2>>c;
			for(int i=y1;i<=y2;i++)
				for(int j=x1;j<=x2;j++)
					table[i][j]=c;
		}
		else if(cmd=='C')
		{
			for(int i=0;i<101;i++)
				for(int j=0;j<101;j++)
					table[i][j]='O';
		}
		else if(cmd=='X')
			break;
		else
		{
			cin.ignore();
			getline(cin,s);
		}
	}
}

Uva 389: Basically Speaking

解題心得

先把數字轉回十進位,再轉成要求的進位制表示法。

程式碼

#include <iostream>
using namespace std;

int to_decimal(string s, int base)
{
	int ans = 0;
	for (int i = 0; i < s.size(); i++)
	{
		if ('0' <= s[i] && s[i] <= '9')
			ans = ans * base + s[i] - '0';
		else
			ans = ans * base + s[i] - 'A' + 10;
	}
	return ans;
}
string convert(int n, int base)
{
	string s = "";
	while (n > 0)
	{
		int tmp = n % base;
		if (tmp >= 10)
			s = char(tmp - 10 + 'A') + s;
		else
			s = char(tmp + '0') + s;
		n /= base;
	}
	while (s.size() < 7)
		s = "0" + s;
	while (s.size() > 7)
		s = s.erase(0, 1);
	return s;
}

int main()
{
	string origin;
	int origin_base, new_base;
	while (cin >> origin)
	{
		cin.ignore();
		cin >> origin_base >> new_base;
		int decimal = to_decimal(origin, origin_base);
		cout << convert(decimal, new_base) << endl;
	}
	return 0;
}

2022年2月2日 星期三

Uva 458: The Decoder

解題心得

CPE第二題居然比第一題簡單

程式碼

#include <iostream>
using namespace std;

int main()
{
	string s;
	while(cin>>s)
	{
		for(int i=0;i<s.size();i++)
			cout<<char(s[i]-7);
		cout<<endl;
	}
	return 0;
}

Uva 10050: Hartals

解題心得

如果先判斷日期是不是週五週六,反而會超時QQ

程式碼

#include <iostream>
using namespace std;

int main()
{
	int T,n,p,h[101]={0};
	cin>>T;
	while(T--)
	{
		int ans=0;
		cin>>n>>p;
		for(int i=0;i<p;i++)
			cin>>h[i];
		for(int i=1;i<=n;i++)
		{
			for(int j=0;j<p;j++)
			{
				if(i%h[j]==0&&i%7!=0&&i%7!=6)
				{
					ans++;
					break;
				}
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

2022年2月1日 星期二

Uva 11960: Divisor Game

解題心得

原本的想法是用質數篩法建質數表,然後一個個用質因數分解找因數,因為一個數的因數數量就是質因數次方加一的乘積。

例:36 = 2^2 + 3^2,其因數數量為(2+1)*(2+1)=9。背後原因很簡單就不贅述。

不過寫完後發現會TLE,只好放棄。

參考了CPE提供的參考解法,發現解法其實很簡單。首先同樣要建表,這次建的是因數表。何謂因數?就是某數可以整除的數。反過來想,把某數的倍數與自己通通都加一,因為一定能整除。

為了近一步縮短時間,提前建好答案表。答案表紀錄從1~i的範圍內,因數數量最多的是誰。注意若數量相同,也要更新。

講起來很容易,但就是想不到啊。

程式碼

#include <iostream>
using namespace std;

#define SIZE 1000001

int table[SIZE] = { 0 }, ans[SIZE] = { 0 };

int main()
{
	for (int i = 1; i < SIZE; i++)
	{
		for (int j = i; j < SIZE; j += i)
			table[j]++;
	}
	int maxIndex = 1, maxCount = 0;
	for (int i = 1; i < SIZE; i++)
	{
		if (table[i] >= maxCount)
		{
			maxIndex = i;
			maxCount = table[i];
		}
		ans[i] = maxIndex;
	}
	
	int T, n;
	cin >> T;
	while (T--)
	{
		cin >> n;
		cout << ans[n] << endl;
	}
	return 0;
}

Uva 11536: Smallest Sub-Array

解題心得

參考網路解法才寫出來。

這題似乎要用到two pointer的概念的變化題。

先假設用一個queue來記錄所有sequence中1~k數字的index,以及countk紀錄當下蒐集到1~k中的總共幾個數字,跟一個array來記錄i最後出現的位置。

每次遇到1~k數字,就先丟進queue中。接著檢查是否第一次遇到這個數字(有沒有在queue中,也就是有沒有在highlight起來的範圍內),若沒有,則更新countk。最後,我們要檢查highlight範圍左側是不是要變化了,判斷方法是看範圍內的最左側,若去掉該位置,依然能保有1~k的數字,那就可以放棄,一直重覆到不能為止。

那又要怎麼確保會找到最短長度呢?首先我們知道當countk==k時就是一組解,而我們的解法是從頭到尾掃過一次並且動態更新,那麼只要每次都檢查當前的解是否更小即可。

另外我在比較cpe提供的參考解法與網路其他人解法時,一開始不懂為何countk只要++,不考慮--的情況。這是因為只有一開始才是還沒找到解的狀態,只要一找到符合的解,只會不斷解查是不是要更新邊界,但也會確保始終是保持1~k數字的區間。

程式碼 

#include <iostream>
#include <queue>
using namespace std;

int seq[1000001] = { 1,2,3 };

int main()
{
	int T;
	cin >> T;
	for (int round = 1; round <= T; round++)
	{
		int n, m, k;
		cin >> n >> m >> k;

		for (int i = 3; i < n; i++)
			seq[i] = (seq[i - 1] + seq[i - 2] + seq[i - 3]) % m + 1;

		queue<int> q;
		int countK = 0, last_pos[101] = { 0 }, ans = 1000001;
		for (int i = 0; i < 101; i++) last_pos[i] = -1;
		for (int i = 0; i < n; i++)
		{
			if (seq[i] <= k)
			{
				q.push(i);
				if (last_pos[seq[i]] == -1) countK++;
				last_pos[seq[i]] = i;

				while (q.front() != last_pos[seq[q.front()]])
					q.pop();
				if (countK == k)
					ans = min(ans, i - q.front() + 1);
			}
		}
		cout << "Case " << round << ": ";
		if (ans == 1000001) cout << "sequence nai" << endl;
		else cout << ans << endl;
	}
	return 0;
}