11418 – Clever Naming Patterns


You’re given a list of problems each can have one of multiple candidate names. You’re required to pick a name for each problem so that no two problem have names that start with the same latter.

There’s an acceptable brute-force solution. However, a maximum flow solution looks nicer.
We’ll have a source, a sink and two layers of nodes. The first layer contains 26 nodes that represent the alphabet. The second layer contains nodes that represent the problems. Each node in the first layer is connected to the source and each noce in the second layer is connected to the sink. Each problem p that has a candidate name that starts with a letter c is connected to the node that represents that letter (c,p).
If we run the Edmond-Karp maximum flow algorithm we should get a maximum flow equal to the number of problems. By examining the graph after the execution, we can find which letter is assigned to which problem.

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cctype>
#include <limits>
#include <string>
#include <queue>
#include <map>
using namespace std;

#define N 54
typedef map<int, int>::iterator itr;
map<int, int> res[N];
int parent[N], s = N - 2, t = N - 1;

bool bfs() {
	queue<int> q;
	q.push(s);
	memset(parent, -1, sizeof parent);
	parent[s] = s;
	while (q.size()) {
		int u = q.front();
		q.pop();
		if (u == t)
			return true;
		for (itr it = res[u].begin(); it != res[u].end(); ++it)
			if (parent[it->first] == -1 && it->second > 0)
				parent[it->first] = u, q.push(it->first);
	}
	return false;
}

int maxFlow() {
	int mf = 0, f, v;
	while (bfs()) {
		// min
		v = t;
		f = numeric_limits<int>::max();
		while (parent[v] != v)
			f = min(f, res[parent[v]][v]), v = parent[v];
		// update
		v = t;
		mf += f;
		while (parent[v] != v)
			res[parent[v]][v] -= f, res[v][parent[v]] += f, v = parent[v];
	}
	return mf;
}

int main() {
	string str;
	int nCase, nProblem;
	map<char, string> pNames[28];
	cin >> nCase;
	for (int caseI = 0; caseI < nCase; ++caseI) {
		// init
		cin >> nProblem;
		for (int i = 0; i < N; ++i)
			res[i].clear();
		for (int i = 0; i < nProblem; ++i) {
			pNames[i].clear();
			res[s][26 + i] = 1;
			res[i][t] = 1;
		}
		// input
		for (int i = 0, nName; i < nProblem; ++i) {
			cin >> nName;
			for (int j = 0; j < nName; ++j) {
				cin >> str;
				str[0] = toupper(str[0]);
				for (int k = 1; k < str.length(); ++k)
					str[k] = tolower(str[k]);
				pNames[i][str[0]] = str;
				res[str[0] - 'A' + 26][i] = 1;
			}
		}
		// solve
		maxFlow();
		cout << "Case #" << (caseI + 1) << ":\n";
		for (int i = 0; i < nProblem; ++i)
			for (itr it = res[i + 26].begin(); it != res[i + 26].end(); ++it)
				if (!it->second) {
					cout << pNames[it->first][i + 'A'] << endl;
					break;
				}
	}
	return 0;
}

TopCoder – SRM570


  • Div2 – 250

    You’re required to count the number of equal-valued pairs in an array. Get the frequency of each value, divide by two and sum that up.

    #include<vector>
    #include<map>
    using namespace std;
    
    class Chopsticks {
    public:
    	int getmax(vector <int> length);
    };
    int Chopsticks::getmax(vector <int> length) {
    	map<int, int> freq;
    	for (int i = 0; i < length.size(); ++i)
    		freq[length[i]]++;
    	int ans = 0;
    	for (map<int, int>::iterator itr = freq.begin(); itr != freq.end(); ++itr)
    		ans += itr->second / 2;
    	return ans;
    }
    
  • Div2 – 500

    A simple simulation problem. You’re given a list of commands a that you’re required to follow T times. Output the manhattan distance you have travelled. Each command is an integer that determines the distance you have to travel and the rotation you have to do. After following command i, you have travelled a distance of a[i] and rotated an angle of 90 * a[i] to the right.
    The naieve solution is acceptable.

    #include <vector>
    #include <cmath>
    using namespace std;
    typedef long long int64;
    
    int dx[4] = { 1, 0, -1, 0 };
    int dy[4] = { 0, 1, 0, -1 };
    
    class RobotHerbDiv2 {
    public:
    	int getdist(int T, vector<int> a);
    };
    int RobotHerbDiv2::getdist(int T, vector<int> a) {
    	int x = 0, y = 0, d = 0;
    	for (int j = 0; j < T; ++j) {
    		for (int i = 0; i < a.size(); ++i) {
    			x += a[i] * dx[d];
    			y += a[i] * dy[d];
    			d += a[i], d %= 4;
    		}
    	}
    	return abs(x) + abs(y);
    }
    
  • Div2 – 1000

    Given a tree R , count the number of its subtrees (a subtree here is any tree r \subseteq R ).
    Think of this recursively; If we have a tree rooted at node R with m children and each child C_i has T(C_i) possible subtrees, we need to find is T(R) .

    T(R) =\\  1\\  +T(C_1)+T(C_2)+T(C_3)...+T(C_m)\\  +T(C_1)T(C_2)+T(C_1)T(C_3)...+T(C_{m-1})T(C_m)\\  +...\\  +T(C_1)T(C_2)T(C_3)T(C_4)...T(C_{m-1})T(C_m)\\  = (1 + T(C_1)) (1 + T(C_2)) ... (1 + T(C_m))  (R)'s \; subtrees = \\  +(R) \; only \\  +(R) \; with \; 1 \; child \; C_i\\  +(R) \; with \; 2 \; children \; C_i C_j \\  +... \\  +(R) \; with \; m \; children \; C_1 C_2 ... C_m \\  = computable \; version

    We use this last formula recursively to get the number of possible trees rooted at R as a function of its children. If we sum that up on all the nodes in the tree, we have counted all the possible subtrees rooted at any node.

    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <vector>
    #include <map>
    using namespace std;
    
    typedef long long int64;
    
    class CentaurCompanyDiv2 {
    	vector<map<int, int> > graph;
    	long long *dp;
    	long long rec(int n);
    public:
    	long long count(vector<int> a, vector<int> b);
    };
    long long CentaurCompanyDiv2::rec(int n) {
    	if (dp[n])
    		return dp[n];
    	long long ans = 1;
    	for (map<int, int>::iterator itr = graph[n].begin();
    				itr != graph[n].end(); ++itr)
    		ans *= 1 + rec(itr->first);
    	return dp[n] = ans;
    }
    long long CentaurCompanyDiv2::count(vector<int> a, vector<int> b) {
    	graph = vector<map<int, int> >(a.size() + 1);
    	for (int i = 0; i <= a.size(); ++i)
    		graph[i].clear();
    	for (int i = 0; i < a.size(); ++i)
    		graph[a[i] - 1][b[i] - 1] = 1;
    	dp = (long long *) malloc(graph.size() * sizeof(long long));
    	memset(dp, 0, sizeof dp);
    	long long ans = 0;
    	for (int i = 0; i < graph.size(); ++i)
    		ans += rec(i);
    	return ans + 1;
    }
    
  • 484 – The Department of Redundancy Department


    Count and print. C++ code:

    #include <cstdio>
    #include <vector>
    #include <map>
    using namespace std;
    
    typedef long long int64;
    
    map<int64, int64> nInput;
    vector<int64> input;
    int64 n;
    
    int main() {
    	// input
    	while (scanf("%lld", &n) == 1) {
    		if (!nInput[n])
    			input.push_back(n);
    		nInput[n]++;
    	}
    	// output
    	for (unsigned int i = 0; i < input.size(); ++i)
    		printf("%lld %lld\n", input[i], nInput[input[i]]);
    	return 0;
    }
    

    10226 – Hardwood Species


    A simple sorting and counting problem.

    #include <string>
    #include <cstdio>
    #include <map>
    using namespace std;
    
    map<string, long long> nTree;
    int nCase, nTreeTot;
    char line[64];
    
    int main() {
    	gets(line);
    	sscanf(line, "%d", &nCase);
    	gets(line);
    	for (int caseI = 0; caseI < nCase; ++caseI) {
    		// init
    		if (caseI)
    			printf("\n");
    		nTreeTot = 0;
    		nTree.clear();
    		// input & slove
    		for (string t; gets(line) && line[0]; ++nTree[t], ++nTreeTot)
    			t = string(line);
    		// print
    		for (map<string, long long>::iterator it = nTree.begin(); it != nTree.end(); ++it)
    			printf("%s %.4lf\n", it->first.c_str(), 100.0 * it->second / nTreeTot);
    	}
    	return 0;
    }
    

    10260 – Soundex


    A simple ad-hoc problem. C++ implementation:

    #include <cstdio>
    #include <map>
    using namespace std;
    
    map<char, char> m;
    char in[32], out[32], prev;
    int outI;
    
    int main() {
    	m['B'] = m['F'] = m['P'] = m['V'] = '1';
    	m['C'] = m['G'] = m['J'] = m['K'] = m['Q'] = m['S'] = m['X'] = m['Z'] = '2';
    	m['D'] = m['T'] = '3';
    	m['L'] = '4';
    	m['M'] = m['N'] = '5';
    	m['R'] = '6';
    	while (scanf("%s", in) == 1) {
    		outI = 0;
    		prev = '7';
    		for (int i = 0; in[i]; ++i)
    			if (m.find(in[i]) != m.end()) {
    				if (m[in[i]] != prev)
    					prev = out[outI++] = m[in[i]];
    				prev = m[in[i]];
    			} else
    				prev = in[i];
    		out[outI] = '\0';
    		printf("%s\n", out);
    	}
    	return 0;
    }