注意set中lower_bound(x)函数的使用
它返回的是一个指向set中第一个不大于x的位置的迭代器,再往前一个位置就是【set中第一个小于x的数的位置】
#include<cstdio>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
vector<int> vx;
vector<int> vy;
//随着色块的增加,有些痕迹被掩盖,有些痕迹新增。
//如果倒着思考,就只需要考虑哪些痕迹是新增的。
//显然新增的痕迹长度,就是这个色块的坐标值,
//与原顺序中后来色块中第一个坐标值小于它的色块坐标值的差值,
//也就是说这个色块被后来的新色块掩盖了一部分。
//在倒序访问中,每访问一个就把它的数据丢进set里就好了,
//因为相对于下一个要访问的色块,它们都是"后来的" 。
int solve(vector<int> v){
int ans=0;
int l=v.size();
set<int> s;
for(int i=l-1;i>=0;i--){
set<int>::iterator it=s.lower_bound(v[i]);
if(it==s.begin()) ans+=v[i];
//迭代器指向第一个元素,说明v[i]比set中元素要小,
//结合题意,它的另一个轴坐标应是对应set中最大的,
//否则它被完全覆盖。
//这也意味着这个v[i]没有被后来的色块掩盖过,是完整的。
else{
it--;
ans+=v[i]-*it;
}
//访问完一个元素,丢进set里
s.insert(v[i]);
}
return ans;
}
int main()
{
int n;
scanf("%d",&n);
while(n--){
int x,y;
scanf("%d%d",&x,&y);
vx.push_back(x);
vy.push_back(y);
}
printf("%d",solve(vx)+solve(vy));
return 0;
}
算法:多源BFS(vector与队列的结合,前者用于储存需要进行相同动作的“源”)
只能所有地块一步一步走,不能一个地块一口气走完s[i]步
#include<cstdio>
#include<iostream>
#include<queue>
#include<vector>
#include<string.h>
const int maxn=1000+10;
using namespace std;
struct node{
int x;
int y;
};
vector<node> v[10];
queue<node> q;
int dx[]={0,0,1,-1};
int dy[]={1,-1,0,0};
int dis[maxn][maxn];
int map[maxn][maxn];
int n,m,p;
int step[10];
int amount[10];
int bfs(int player){
//针对玩家player的当前所有可扩展的地块的某一步数的可行方案搜索,返回值是可用于继续扩展的地块数量
for(int i=0;i<v[player].size();i++) q.push(v[player][i]);
v[player].clear();
//将所有的“源”取出,加入队列
while(!q.empty()){
node t1=q.front();
q.pop();
int sx=t1.x;
int sy=t1.y;
for(int i=0;i<4;i++){
int nx=sx+dx[i];
int ny=sy+dy[i];
if(nx<1||ny<1||nx>n||ny>m||map[nx][ny]==-1) continue;
if(dis[nx][ny]!=-1) continue;
dis[nx][ny]=dis[sx][sy]+1;
//用于标记这是第几步走到的地块,初始地块的值为0
amount[player]++;
//统计已占据地块数量
node t2;
t2.x=nx;t2.y=ny;
v[player].push_back(t2);
//加入新的“源”,以进行下一次扩展操作
}
}
return v[player].size();
}
int main()
{
cin>>n>>m>>p;
for(int i=1;i<=p;i++) cin>>step[i];
memset(dis,-1,sizeof(dis));
//注意此处对地图的处理,用getchar()
for(int i=1;i<=n;i++){
char c=getchar();
//行首先吞换行符
for(int j=1;j<=m;j++){
c=getchar();
//读取地图格子
if(c=='.') map[i][j]=0;
else if(c=='#') map[i][j]=-1;
else {
map[i][j]=c-'0';
//将字符数字转为整型数字
dis[i][j]=0;
//记录初始地块
node start;
start.x=i;start.y=j;
v[c-'0'].push_back(start);
//作为“源”加入
amount[c-'0']++;
//统计已占据地块数量
}
}
}
while(1){//一次循环代表一个回合
int Full=1;//用于判断还有无可占据地块的哨兵,只要还有一个玩家的vector没有清空,它的值就会被改变
for(int i=1;i<=p;i++){
for(int j=1;j<=step[i];j++){
if(!bfs(i)) break;
else Full=0;
}
}
if(Full) break;
}
for(int i=1;i<=p;i++) cout<<amount[i]<<" ";
return 0;
}