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 a
iter = 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;
}