谷歌中国算法比赛解题报告 APAC2017C
Problem A.?Monster Path
Problem B.?Safe Squares
Problem C.?Evaluation
Problem D.?Soldiers
終于快寫完了,lz也越來越懶。。。
考試的時候lz異想天開用python刷題……結果你懂的……lz的python畢竟也不熟練
這題前三題不說了(好吧我沒做),說說第四題
這題很難,如果用標準的博弈思想,算法復雜度是O(n4),大數據托托超時
但是這題可以優化,優化后能達到O(n2)!!!
首先分析一下標準做法,DFS, 哪怕我們記錄每一步的結果,我們還是找了太多的無效節點,要知道要判斷這個點能不能贏,我們要判斷以這個點為起點的所有情況中,有沒有一個對方的失敗點,而這情況太多了
但是這題可以倒過來找,跟APAC2015有一道addtion很像,倒著找,所有無效的節點都不用管了!!!
首先,A,D都取最大值一定是一個勝點,如果這個點存在卡牌,直接返回勝利
如果不存在,則橫著掃描,所有A,其它D,都是負點,因為攻擊為D的卡牌必然有,如果我選了A,其它D,那么你可以選任意A,D這張卡
同理,豎著掃,所有 其它A,D都是負點
然后掃到第二行第二列的點,這個點的正上方的列點如果都是負點,并且這個點的正左方的點如果都是負點,這個點就是勝點,然后這個點正右方,正下方就都變成負點,如果這個點上方或左方有勝點,那么它就是負點
對于勝點,查看能不能選到,選到就返回,
否則,繼續往后掃,如果掃的點已經處理過,就跳過
這樣是O(n3) 但其實我們對每個點,只要查上方一個點和左方一個點就好,具體原因,自己想……
這樣就是O(n2)
說的不是很清楚(lz承諾……要是過了E,你懂的……),具體怎么搞,請看代碼……
#include <stdio.h> #include <iostream> #include <fstream> #include <math.h> #include <algorithm> #include <vector> #include <set> #include <map> #include <hash_map> #include <hash_set> #include <unordered_map> #include <unordered_set> #include <string.h> #include <queue> #include <list>using namespace std;#define real long long//DFS 做法,耗時n4 class CD { public:CD(){}int M, N;map<int, set<int>> amap;map<int, set<int>> dmap;map<int, map<int,int>> winMap;int checkWinLose(int a, int d){map<int, map<int, int>>::iterator it1;map<int, int>::iterator it2;it1 = winMap.find(a);if (it1 != winMap.end()){it2 = it1->second.find(d);if (it2 != it1->second.end()){return it2->second;}}return 0;}void setWinPoint(int a, int d,int sign=1){winMap[a][d] = sign;map<int, set<int>>::iterator iter, iter2;if (*(dmap[d].begin()) < a){for (iter = dmap.begin(); iter != dmap.end() && iter->first < d; iter++){winMap[a][iter->first] = -sign;}}if (*(amap[a].begin()) < d){for (iter = amap.begin(); iter != amap.end() && iter->first < a; iter++){winMap[iter->first][d] = -sign;}}}bool DFS(int a, int d){map<int, set<int>>::iterator iter, iter2;iter = amap.end();iter--;for (; iter != amap.end()&&iter->first>a;iter--){set<int>::iterator siter;for (siter = iter->second.begin(); siter != iter->second.end();siter++){int na, nd;na = iter->first;nd = max(*siter, d);int k = checkWinLose(na,nd);if (k == -1){setWinPoint(a, d);return true;}else if (k == 1){continue;}else{bool r=DFS(na, nd);if (r){continue;}else{setWinPoint(a, d);return true;}}}}//same as aiter = dmap.end();iter--;for (; iter != dmap.end() && iter->first>d; iter--){set<int>::iterator siter;for (siter = iter->second.begin(); siter != iter->second.end();siter++){int na, nd;na = max(*siter,a);nd = iter->first;int k = checkWinLose(na, nd);if (k == -1){setWinPoint(a, d);return true;}else if (k == 1){continue;}else{bool r = DFS(na, nd);if (r){continue;}else{setWinPoint(a, d);return true;}}}}setWinPoint(a, d, -1);return false;}string SingleProcess(){amap[0].insert(0);dmap[0].insert(0);setWinPoint(amap.rbegin()->first, dmap.rbegin()->first,-1);if (DFS(0, 0)){return "YES";}return "NO";}void run(){FILE* fp = freopen("in.txt", "r", stdin);ofstream fout("out.txt");int Cases = 0;scanf("%d", &Cases);for (int time = 0; time < Cases; time++){scanf("%d", &N);int A, D;amap.clear();dmap.clear();winMap.clear();for (int i = 0; i < N; i++){scanf("%d %d", &A, &D);amap[A].insert(D);dmap[D].insert(A);}fout << "Case #" << (time + 1) << ": " << SingleProcess().c_str() << endl;std::cout << time << endl;}fclose(fp);fout.close();} };//濃縮后倒著推,找到一個就返回,最大耗時n2,但condense比較耗時,關鍵點,找一個點是不是勝點只要考慮該行該列(再優化到只考慮比它大一的行列),而DFS要找的是比自身大的所有行所有列。如果不condense,向上移動的操作比較麻煩。 class CX1 { public:CX1(){}int M, N;int MA, MD;struct INT2{int x, y;INT2(){ x = y = 0; }};map<int,int> amap;map<int,int> dmap;vector<int> cmin;vector<int> rmin;vector<INT2> solders;vector<vector<bool>> matrix;vector<vector<int>> winMap;string SingleProcess(){for (int r = MA - 1; r > 0;r--){for (int c = MD - 1; c > 0; c--){if (winMap[r][c] != 0) continue;bool findone = false;if(r+1 < MA){if (winMap[r+1][c] == -1 && c>rmin[r+1]){findone = true;for (int j = r; j > 0; j--) winMap[j][c] = 1;}}if (!findone&&c+1<MD){if (winMap[r][c+1] == -1 && r>cmin[c+1]){findone = true;for (int j = c; j > 0; j--) winMap[r][j] = 1;}}if (!findone){winMap[r][c] = -1;if (matrix[r][c]) return "YES";}}}return "NO";}void run(){FILE* fp = freopen("in.txt", "r", stdin);ofstream fout("out.txt");int Cases = 0;scanf("%d", &Cases);for (int time = 0; time < Cases; time++){scanf("%d", &N);amap.clear();dmap.clear();solders.clear();cmin.clear();rmin.clear();solders.resize(N, INT2());winMap.clear();for (int i = 0; i < N; i++){scanf("%d %d", &solders[i].x, &solders[i].y);amap[solders[i].x] = 0;dmap[solders[i].y] = 0;}MA = MD = 1;for (map<int, int>::iterator iter = amap.begin(); iter != amap.end(); iter++){iter->second = MA++;}for (map<int, int>::iterator iter = dmap.begin(); iter != dmap.end(); iter++){iter->second = MD++;}matrix.clear();matrix.resize(MA, vector<bool>(MD,false));winMap.clear();winMap.resize(MA, vector<int>(MD, 0));cmin.resize(MD, INT_MAX);rmin.resize(MA, INT_MAX);for (int i = 0; i < solders.size(); i++){int t1 = amap[solders[i].x];int t2 = dmap[solders[i].y];matrix[t1][t2] = true;cmin[t2] = min(cmin[t2], t1);rmin[t1] = min(rmin[t1], t2);}fout << "Case #" << (time + 1) << ": " << SingleProcess().c_str() << endl;std::cout << time << endl;}fclose(fp);fout.close();} };//不condense,充分使用map,但利用了題目中10000*10000的數組,否則只能condense //紅黑樹做索引,vector做存儲matrix,利用10000*10000,效率很高!!! class CX2 { public:CX2(){}int M, N;int MA, MD;struct INT2{int x, y;INT2(){ x = y = 0; }};map<int, set<int>> amap;map<int, set<int>> dmap;//map<int, map<int, int>> winMap; //紅黑樹不能處理,速度太慢而且內存占用非常高//unordered_map<int, unordered_map<int, int>> winMap; //hash表的速度依然慢到爆表,而且內存占用非常高,和紅黑樹差不多vector<vector<int>> winMap; //vector可以處理,綜合速度比condense慢一些,但不太大,畢竟10000*10000和4000*4000的區別,內存上差很多string SingleProcess(){map<int, set<int>>::iterator aiter, diter,t1,t2;set<int>::iterator siter;map<int, int> temp;for (aiter = amap.end(), aiter--; aiter != amap.end(); aiter--){for (diter = dmap.end(), diter--; diter != dmap.end(); diter--){if (winMap[aiter->first][diter->first]!=0) continue;//這個winMap必然要填滿,所以就這么寫了bool findone = false;t1 = aiter;t1++;if (t1 != amap.end() && winMap[t1->first][diter->first] == -1 && diter->first>*(t1->second.begin())){findone = true;for (t1 = aiter; t1 != amap.end(); t1--) winMap[t1->first][diter->first] = 1;}t1 = diter;t1++;if (!findone&&t1!=dmap.end()&&winMap[aiter->first][t1->first]==-1&&aiter->first>*(t1->second.begin())){findone = true;for (t1 = diter; t1 != dmap.end(); t1--) winMap[aiter->first][t1->first] = 1;}if (!findone){winMap[aiter->first][diter->first] = -1;if (amap[aiter->first].find(diter->first)!=amap[aiter->first].end()) return "YES";}}}return "NO";}void run(){FILE* fp = freopen("in.txt", "r", stdin);ofstream fout("out.txt");int Cases = 0;scanf("%d", &Cases);for (int time = 0; time < Cases; time++){scanf("%d", &N);amap.clear();dmap.clear();winMap.clear();winMap.resize(10001, vector<int>(10001,0));int A, D;for (int i = 0; i < N; i++){scanf("%d %d", &A,&D);amap[A].insert(D);dmap[D].insert(A);}fout << "Case #" << (time + 1) << ": " << SingleProcess().c_str() << endl;std::cout << time << endl;}fclose(fp);fout.close();} };int main() {//CA p;//CB p;//CC p;CX2 p;p.run();return 0; }總結
以上是生活随笔為你收集整理的谷歌中国算法比赛解题报告 APAC2017C的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么降低照片大小kb?
- 下一篇: 用 ABAP 新建本地 Excel 文件