您的位置:首页 > 编程语言 > Go语言

Google APAC Round D题解

2015-11-08 23:30 393 查看
Problem A. Dynamic Grid

最基础的搜索,我用DFS做的,标记棋盘上每一个位置初始化为未搜索,遍历整个棋盘,如果遇到1且以前从没搜索到的话就从该点开始不停搜索,直到搜完,复杂度O(m*n)

代码

int m, n;
int q;
char b[110][110];
bool flag[110][110];
bool valid(int x ,int y)
{
if(x < 0 || x >= m)
return false;
if(y < 0 || y >= n)
return false;
if(flag[x][y] == 1)
return false;
if(b[x][y] != '1')
return false;
return true;
}
void DFS(int x ,int y)
{
flag[x][y] = 1;
if(valid(x - 1, y))
DFS(x - 1, y);
if(valid(x + 1, y))
DFS(x + 1, y);
if(valid(x, y - 1))
DFS(x, y -1);
if(valid(x, y + 1))
DFS(x, y + 1);
}
int solve()
{
ZERO(flag);
int count = 0;
FOR(i,0,m)
FOR(j,0,n)
{
if(b[i][j] == '1' && flag[i][j] == false)
{
DFS(i,j);
count++;
}
}
return count;
}
int main(){
int Tcase;
cin >> Tcase;

FOR(hh,0,Tcase)
{
cin >> m >> n;
FOR(i,0,m)
FOR(j,0,n)
cin >> b[i][j];
cin >> q;
cout << "Case #" << hh + 1 << ":" << endl;
char ops;
FOR(i,0,q)
{
cin >> ops;
if(ops == 'Q')
cout << solve() << endl;
else
{
int x ,y;
char val;
cin >> x >> y >> val;
b[x][y] = val;
}
}
}

return 0;
}


Problem B. gBalloon

很有意思的题目,首先考虑不可能的情况:

1.如果风向和距离的乘积为正数或者0(距离不为0),那么一定需要移动这个气球(称之为坏球),记下所需要的最小的消耗,如果所有坏球所需最小消耗的和大于q,那么不可能。

2.考虑如果需要移动气球,那么肯定是在时刻0的时候移动,我们用set维护一个3-element entry记录(当前气球标号,该球消耗的能量,到达0位置所需要的时间),并按最后一项的值从大向小排序。初始化时所有好球消耗的能量为0,时间根据dis/v向上取整。所有坏球计算所需最小的消耗和时间。每次从set中拿出第一位的项(时间最长),因为是它限制了最后到达的时间,给他能量看能否快过第二项,如果在当前能量+之前消耗的 可以保证他快过第二项,那么更新该项并且重新插入,同时更新剩余的能量。如果不能的话则循环结束,将所有的剩余能量尝试更新最开始的项,返回该项所需的时间。

因为每次消耗的q会最少增加1,所以总得复杂度是O(q * m * logn)

#define FOR(a, b, n) for(int (a) = (b); (a) < (n); ++(a))
#define ITE(a, v) for(auto (a) = v.begin(); (a) != v.end(); ++(a))
#define LL long long
#define ALL(v) v.begin(),v.end()
#define ZERO(v) memset(v, 0, sizeof v)
#define NEG(v)  memset(v, -1, sizeof v)
#define F first
#define S second
#define PB push_back
#define MP make_pair
#define MOD 1000000007
#define PI 3.141592653589793
inline long double min(long double a , long double b) {if(a < b)return a; return b;}
inline long double max(long double a , long double b) {if(a < b)return b; return a;}

int m, n;
int q;
int speed[1100];
pair<int,int> pos[110];

set<pair<int,int>,greater<pair<int,int> > > uset;
int calc(int p, int s)
{
if(p * s >= 0)
return INT_MAX;
int t = p / s;
if(t * s == p)
return abs(t);
else
return abs(t) + 1;
}
int solve()
{
int sum = 0;
int flag[110];
int energy[110];
ZERO(energy);
ZERO(flag);
FOR(i,0,n)
{
if(pos[i].first == 0)
continue;
int p = pos[i].first;
int h = pos[i].second;
if(speed[h] * p == 0 || speed[h] * p > 0)
{
flag[i] = 1;
}
else
{
int t = p / speed[h];
if(t * speed[h] == p)
uset.insert(MP(abs(t),i));
else
uset.insert(MP(abs(t) + 1, i));
}
}
int eng = 0;
FOR(i,0,n)
{
if(!flag[i])
continue;
int p = pos[i].first;
int h = pos[i].second;
int MIN = q + 1;
int index = -1;
for(int j = 0; j < m; j++)
{
if(speed[j] * p < 0)
{
if(abs(j - h) < MIN)
{
MIN = abs(j - h);
index = j;
}
}
}
if(index == -1)
return -1;
int t = p / speed[index];
if(speed[index] * t == p)
uset.insert(MP(abs(t), i));
else
uset.insert(MP(abs(t) + 1, i));
flag[i] = MIN;
energy[i] = MIN;
eng += MIN;
}
if(eng > q)
return -1;
int remain = q - eng;
while(remain > 0)
{
pair<int,int> slow = *(uset.begin());

uset.erase(uset.begin());
int limit = slow.first;
if(uset.size())
limit = uset.begin()->first;
int ii = slow.second;
int p = pos[ii].first;
int h = pos[ii].second;
remain += energy[ii];
int index=  -1;
int MIN = m + 1;
int T = -1;
for(int i = max(0, h - remain); i <= min(m - 1, h + remain); i++)
{
int tt = calc(p, speed[i]);

if(tt < limit)
{
if(abs(i - h) < MIN)
{
MIN = abs(i - h);
index = i;
T = tt;
}
}
}

if(index == -1 || remain < MIN)
{
uset.insert(slow);
break;
}
energy[ii] = MIN;
remain -= MIN;
uset.insert(MP(T,ii));
}
int ii = uset.begin()->second;
int tt = uset.begin()->first;
int p = pos[ii].first;
int h = pos[ii].second;

for(int i = max(0, h - remain); i <= min(m - 1, h + remain); i++)
{
int t = calc(p, speed[i]);
tt = min(tt,t);
}

return tt;

}
int main(){
int Tcase;
cin >> Tcase;

FOR(hh,0,Tcase)
{
cin >> n >> m >> q;
FOR(i,0,m)
cin >> speed[i];
FOR(i,0,n)
cin >> pos[i].first >> pos[i].second;
cout << "Case #" << hh + 1 << ": ";
uset.clear();
int res = solve();
if(res != -1)
cout << res << endl;
else
cout << "IMPOSSIBLE" << endl;
}

return 0;
}


Problem C. IP Address Summarization

这题当时卡了挺长时间,题意就是求最小的能表示当前网段的一个集合,因为比如1.0.0.0/9和1.128.0.0/9是可以合写成1.0.0.0/8的。对于斜杠后面的数我称它为掩码最低位。声明32个hashset,对于每个IP,先将其标准化后(和掩码&一下),然后转化为long long(高低位要分清楚,我是按照题意直接记录的,即1.0.0.0为00000001.24个0),因为32位数最高不超过2^32-1。根据掩码最低位的不同insert到不同的hashset里,这样先去重,然后从第32个hashset开始遍历所有的值,如果对第i个hashset的第j个值,设为val,如果val在第i位(从高向低)为1,那么看一下是否val去掉该位的值(val-(1<<(32-i))也在该hashset中,如果在的话就向前一个hashset中插入(val-(1<<(32-i)),当前hashset的不急着删除,反正下一步也会删除掉。

接下来就是去掉重合的subnet,仍旧从第32个hashset开始,对于每一项,如果一个一个去掉2进制中得1之后,所得到的值在之前的某个hashset中出现,则说明前面的subnet可以覆盖当前的,删掉即可。

复杂度为O(32 * 32 * n)

这题本身不难,我写的可能复杂了很多,主要是当时index从0或者从1开始理解起来很混乱,想清楚了以后实现还是很简单,位操作还是能解决很多问题的

#define FOR(a, b, n) for(int (a) = (b); (a) < (n); ++(a))
#define ITE(a, v) for(auto (a) = v.begin(); (a) != v.end(); ++(a))
#define LL long long
#define ALL(v) v.begin(),v.end()
#define ZERO(v) memset(v, 0, sizeof v)
#define NEG(v)  memset(v, -1, sizeof v)
#define F first
#define S second
#define PB push_back
#define MP make_pair
#define MOD 1000000007
#define PI 3.141592653589793
inline long double min(long double a , long double b) {if(a < b)return a; return b;}
inline long double max(long double a , long double b) {if(a < b)return b; return a;}

int n;
unordered_set<LL> uset[33];

string conv(LL val)
{
vector<int> res(4);
for(int i = 3; i >= 0 ; i--)
{
res[i] = val % 256;
val /= 256;
}
string r;
FOR(i,0,res.size())
{
r += to_string(res[i]);
r.PB('.');
}
r.pop_back();
return r;
}
vector<int> split(string s)
{
int pos2 = s.find('.');
int pos1 = 0;
vector<string> res;
while(pos2 != -1)
{
res.PB(s.substr(pos1, pos2 - pos1));
pos1 = pos2 + 1;
pos2 = s.find('.', pos1 );
}
if(pos1 != s.size())
res.PB(s.substr(pos1));
vector<int> ans;
FOR(i,0,res.size())
ans.PB(stoi(res[i]));
return ans;
}
void clearPos(LL &val, LL base)
{
if((val & base) == 0)
return;
val -= base;
}

int main(){
int Tcase;
cin >> Tcase;

FOR(hh,0,Tcase)
{
FOR(i,0,33)
uset[i].clear();
cin >> n;
FOR(i,0,n)
{
string s;
cin >> s;
int pos = s.find('/');
int val = stoi(s.substr(pos + 1));
vector<int> temp = split(s.substr(0,pos));
LL tmp = 0;
LL base = 1;
for(int j = 3; j >= 0; j--)
{
tmp += base * temp[j];
base *= 256;
}
//cout << conv(tmp) << endl;
base = 1LL <<(32 -val);
base /= 2;
for(int j = val + 1; j <= 32; j++,base /= 2)
{
clearPos(tmp,base);
}
uset[val].insert(tmp);
}
LL base = 1;
for(int i = 32; i >= 1; i--, base *= 2)
{
ITE(j,uset[i])
{
LL val = *j;
if((val & base) != 0)
{
LL val2 = val - base;
if(uset[i].count(val2) == 1)
uset[i- 1].insert(val2);
}
else
{
LL val2 = val | base;
if(uset[i].count(val2) == 1)
uset[i- 1].insert(val);
}
}
}
base = 1;
for(int i = 32; i >= 1; i--, base *= 2)
{
vector<LL> E;
ITE(j,uset[i])
{
LL tmpBase = base;
LL val = *j;
clearPos(val, tmpBase);
tmpBase *= 2;
bool flag=  false;
for(int k = i - 1; k >= 0; k--, tmpBase *= 2)
{
if(uset[k].count(val) == 1)
{
flag = true;
break;
}
clearPos(val, tmpBase);
}
if(flag)
E.PB(*j);
}
FOR(j,0,E.size())
uset[i].erase(E[j]);
}
set<pair<LL,int> > ans;
for(int i = 32; i >= 1; i--, base *= 2)
{
ITE(j,uset[i])
{
ans.insert(MP(*j,i));
}
}
cout << "Case #" << hh + 1 << ":" << endl;
ITE(i,ans)
cout << conv(i->first) << "/" << i->second << endl;

// cout << solve() << endl;
}

return 0;
}


Problem D. Virtual Rabbit

没做出来,感觉没什么头绪,待我研究了大神的代码以后补上
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  谷歌