A.走”日”字,判断从(i,j)到(k,l)最少几步走到。(5.17)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
int r,c,gr,gc,lr,lc;
int dirr[9]={0,1,1,2,2,-1,-1,-2,-2};
int dirc[9]={0,2,-2,1,-1,2,-2,1,-1};
struct node{int rr,cc,dis;};
queue<node>q;
bool vis[105][105];
int bfs(int rr,int cc){
memset(vis,0,sizeof(vis));
while(!q.empty()) q.pop();
q.push((node){rr,cc,0});
vis[rr][cc]=1;
while(!q.empty()){
node now=q.front();q.pop();
//printf("%d %d\n",now.rr,now.cc);
for(int i=1;i<=8;i++){
int nr=now.rr+dirr[i];
int nc=now.cc+dirc[i];
if(!vis[nr][nc]&&nr>0&&nc>0&&nr<=r&&nc<=c){
vis[nr][nc]=1;
q.push((node){nr,nc,now.dis+1});
if(nr==lr&&nc==lc) {
return now.dis+1;
}
}
}
}
return -1;
}
int main(){
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
while(~scanf("%d%d%d%d%d%d",&r,&c,&gr,&gc,&lr,&lc)){
if(lr==gr&&lc==gc) {printf("0\n");continue;}
int t=bfs(gr,gc);
if(t==-1) printf("impossible\n");
else printf("%d\n",t);
}
return 0;
}
B.1.求无向图割边,2.在多个环里的边数。N<=10000 M<=100000(5.18)
第一问tarjan求割边。
第二问一个bcc的性质:为一下三种中的一种:
1.两点一边 2.简单环 3.多个简单环,一些简单环有公共边。
所以我们求出bcc,判断 点数<边数 即为情况3。
摘自蓝书:
不难发现,每条边恰好属于一个双连通分量,但不同的双连通分量可能会有公共点。可以证明不同双连通分量最多只有一个公共点,且它是割点。任意割点都是至少两个不同双连通分量的公共点。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#define N 10005
#define M 100005
using namespace std;
struct E {int to,nxt;}edge[M*2];
struct EE {int u,v;};
int n,m,tot,idx[N];
int dfn[N],low[N],dfs_clock,bcc_cnt,bccno[N];
int ans1,ans2,points,edges;
stack<EE>s;
void init(){
tot=2;dfs_clock=0;ans1=0;ans2=0;bcc_cnt=0;
memset(edge,0,sizeof(edge));
memset(idx,0,sizeof(idx));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(bccno,0,sizeof(bccno));
}
void addedge(int from,int to){
edge[tot].to=to;edge[tot].nxt=idx[from];idx[from]=tot++;
}
void dfs(int x,int fa){
dfn[x]=low[x]=++dfs_clock;
for(int t=idx[x];t;t=edge[t].nxt){
E e=edge[t];
EE ee=(EE){x,e.to};
if(!dfn[e.to]){
s.push(ee);
dfs(e.to,x);
low[x]=min(low[x],low[e.to]);
if(low[e.to]>dfn[x]) ans1++;
if(low[e.to]>=dfn[x]){
bcc_cnt++;
edges=0;points=0;
for(;;){
EE xx=s.top();s.pop();edges++;
if(bccno[xx.u]!=bcc_cnt){points++;bccno[xx.u]=bcc_cnt;}
if(bccno[xx.v]!=bcc_cnt){points++;bccno[xx.v]=bcc_cnt;}
if(xx.u==x&&xx.v==e.to) break;
}
if(edges>points) ans2+=edges;
}
}
else if(dfn[e.to]<dfn[x] && e.to!=fa){
s.push(ee);
low[x]=min(low[x],dfn[e.to]);
}
}
}
int main(){
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
while(scanf("%d%d",&n,&m)&&n+m!=0){
init();
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);x++;y++;
addedge(x,y);addedge(y,x);
}
for(int i=1;i<=n;i++)
if(!dfn[i]) dfs(i,0);
printf("%d %d\n",ans1,ans2);
}
return 0;
}
C.
D.n*m的矩形有B,R,选取周长最大的矩形,有三种可选矩形:
a.全为B。b.全为R。c.BR相间。(n,m<=1000)(5.17)
考虑全部为B的情况(b的情况可以对map取反,c可以部分取反,共操作4次),up[],left[],right[],记录像上扩展距离
ans=max(2*((r-l+1)+up));//up!=0
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define N 1005
using namespace std;
int map[N][N];
int T,n,m,ans,tot;
int up[N][N],l[N][N],r[N][N];
void doit(){//1洞
memset(up,0,sizeof(up));
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));
for(int i=1;i<=m;i++)
up[1][i]=map[1][i]==0;
for(int i=2;i<=n;i++)
for(int j=1;j<=m;j++)
up[i][j]=map[i][j]==0?up[i-1][j]+1:0;
/*for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
printf("%d ",up[i][j]);
printf("\n");
}*/
for(int i=1;i<=n;i++){
l[i][1]=1;
for(int j=2;j<=m;j++){
int ll=j;
l[i][j]=j;
while(ll>1&&up[i][j]<=up[i][ll-1])
ll=l[i][ll-1],l[i][j]=ll;
}
r[i][m]=m;
for(int j=m-1;j>=1;j--){
int rr=j;
r[i][j]=j;
while(rr<m&&up[i][j]<=up[i][rr+1])
rr=r[i][rr+1],r[i][j]=rr;
}
}
}
void getans(){
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if(up[i][j]) ans=max(ans,2*(r[i][j]-l[i][j]+1+up[i][j]));
/*for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
printf("%d ",2*(r[i][j]-l[i][j]+1+up[i][j]));
printf("\n");
}*/
}
int main(){
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
scanf("%d",&T);
while(T--){
tot++;
ans=0;
scanf("%d%d\n",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
char ch;
scanf("%c",&ch);
map[i][j]=ch=='B'?1:0;
}
scanf("\n");
}
doit();getans();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
map[i][j]=map[i][j]^1;
doit();getans();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
if((i+j)&1) map[i][j]=map[i][j]^1;
doit();getans();
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
map[i][j]=map[i][j]^1;
doit();getans();
printf("Case #%d: ",tot);
printf("%d\n",ans);
}
return 0;
}
E.
F.n只蚂蚁在一条长度为l的线段上爬。每个蚂蚁有一种颜色,总颜色数为k,三个参数x,c,dir,代表坐标,颜色,方向。当两个蚂蚁(c1,c2)相遇,左边的蚂蚁颜色变为(c1+c2)%k,右边的蚂蚁颜色变为c1,在所有蚂蚁都走完时,求各种颜色的在所有时刻的路程。(n<=100000,l<=1000000,k<=40)(5.18)
观察发现,两个蚂蚁相遇,可以等价于左边的蚂蚁继续走不变色,右边的蚂蚁继续走颜色变为(c1+c2)%k,这样我们可以想到n^2暴力。然而注意到颜色只有40种。我们可以从左到右扫描每种颜色对当前位置的答案的贡献。时间复杂度O(nk)
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 100005
using namespace std;
struct A{int x,c;bool dir;}a[N];
long long s[N][40],ans[N],color_s[N];
int n,k,l,last_r,first_r,f;
int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
bool cmp(A m,A n){return m.x<n.x;}
int main(){
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
scanf("%d%d%d",&n,&k,&l);
for(int i=1;i<=n;i++){
a[i].x=read();a[i].c=read();
a[i].dir=getchar()=='D';
}
sort(a+1,a+1+n,cmp);
if(a[1].x==0&&a[1].dir==0) a[1].dir=1,a[1].c=0,f=1;
else if(a[1].x!=0)
a[n+1].x=0,a[n+1].c=0,a[n+1].dir=1,n++,sort(a+1,a+1+n,cmp),f=1;
for(int i=1;i<=n;i++){
if(!a[i].dir) {
for(int j=0;j<k;j++) s[i][j]=s[i-1][j];
color_s[i]=color_s[i-1];
continue;
}
if(!last_r) {first_r=i;color_s[i]=a[i].c;last_r=i;continue;}
color_s[i]=(color_s[last_r]+a[i].c)%k;
for(int j=0;j<k;j++)
s[i][(j+a[i].c)%k]+=s[i-1][j];
s[i][a[i].c]+=(a[i].x-a[last_r].x);
last_r=i;
}
/*for(int i=1;i<=n;i++) printf("%d ",color_s[i]);puts("");
for(int i=1;i<=n;i++){
for(int j=0;j<k;j++)
printf("%d ",s[i][j]);
printf("\n");
}*/
last_r=0;
for(int i=1;i<=n;i++){
if(a[i].dir) last_r=i,ans[a[i].c]+=2*(l-a[i].x);
else{
for(int j=0;j<k;j++) ans[(a[i].c+j)%k]+=s[i][j];
ans[a[i].c%k]+=(a[i].x-a[last_r].x);
if(i>=first_r) ans[(color_s[i]+a[i].c)%k]+=(a[i].x+a[first_r].x);
}
}
if(f==1) ans[0]-=2*l;
for(int i=0;i<k;i++) printf("%.1lf\n",(double)ans[i]*0.5);
return 0;
}
//0 1 L