upcoj 1975 棋盘覆盖二分匹配+2107单调队列+1109
首先是A题,这题知道用二分做之后自己做了一遍,开始建图没用好思路,然后就想到了建图的方法,主要是二分匹配要注意的点是:2个集合。
确定两个集合之间的关系,而不要在一个集合上自身匹配。
然后就无限WA了,样例和自己列的数据都过了,死磕都WA 后来问肖太爷,他建图方法比我简单多了,我是一个一个枚举搜索来区分组的,他就直接找不相邻的直接分组了,囧囧。
给出自己的挫WA代码吧。好歹思路是对的- -,我已经debug好久了。。。
1975:
//最大匹配 #include<iostream> #include<cstring> using namespace std; int dx[2]={0,-1}; int dy[2]={1,0}; int map[3100][3100]; int g[60][60]; int b[60][60]; int tmp[3100]; int num[60][60]; int flag[3100]; int n,m;int lx,ly; int DFS(int x) { for(int i=0;i<=ly;i++) { if(!flag[i]&&map[x][i]) { flag[i]=1; if(tmp[i]==-1||DFS(tmp[i])) { tmp[i]=x; return 1; } } } return 0; } int main() { int T,i,k,j,sum,count,x,y; cin>>T; while(T--) { cin>>n>>m; for(i=0;i<n;i++) for(j=0;j<m;j++) { cin>>g[i][j]; } //建图 memset(map,0,sizeof(map)); memset(tmp,-1,sizeof(tmp)); memset(b,0,sizeof(b)); memset(num,0,sizeof(num)); count=1;//第一个标记为1集合 lx=-1;ly=-1; //代表1 2 集合的下标 for(i=0;i<n;i++) for(j=0;j<m;j++) { if(!g[i][j]) { if(b[i][j]==0)//1为一个集合 -1为一个集合 0为空洞 { b[i][j]=count; //初始化 lx++;num[i][j]=lx; //num 记录i,j坐标的元素在其集合上的下标 } for(k=0;k<2;k++) { if(i+dx[k]>=0&&i+dx[k]<n&&j+dy[k]>=0&&j+dy[k]<m&&!g[i+dx[k]][j+dy[k]]) { if(b[i+dx[k]][j+dy[k]]==0) { b[i+dx[k]][j+dy[k]]=-b[i][j]; //相邻2点集合必定不同 if(b[i+dx[k]][j+dy[k]]==1){lx++;num[i+dx[k]][j+dy[k]]=lx;} else {ly++;num[i+dx[k]][j+dy[k]]=ly;} //将不同集合的连续两点加入图中 x=num[i][j];y=num[i+dx[k]][j+dy[k]]; if(b[i][j]==1) map[x][y]=1; else map[y][x]=1; } } } } } for(i=0;i<=lx;i++) { cout<<endl; for(j=0;j<=ly;j++) { cout<<map[i][j]<<' '; } } sum=0; for(i=0;i<=lx;i++) { memset(flag,0,sizeof(flag)); sum+=DFS(i); } if(sum%2==1) cout<<"甲"<<endl; else cout<<"乙"<<endl; //cout<<sum<<endl; } }
然后是肖的代码:
#include<stdio.h> #include<algorithm> #include<string.h> #define N 2100 int a[60][60],f[N][N],link[N],v[N],ma[N][N],i,j,k,m,n,x,y,z,t,ans,t1,t2; bool dfs(int x) { int i,j; for (i=1;i<t1;i++) if (!v[i]&&f[x][i]) { v[i]=1; if (link[i]==0||dfs(link[i])) { link[i]=x;return true; } } return false; } int main() { scanf("%d",&t); while (t--) { memset(a,0,sizeof(a)); memset(f,0,sizeof(f)); memset(link,0,sizeof(link)); memset(ma,0,sizeof(ma)); scanf("%d%d",&n,&m); for (i=1;i<=n;i++) for (j=1;j<=m;j++) { scanf("%d",&a[i][j]); a[i][j]=a[i][j]^1; } t1=1,t2=1; for (i=1;i<=n;i++) for (j=1;j<=m;j++) { if ((i+j)%2==1&&a[i][j])ma[i][j]=t1++; if ((i+j)%2==0&&a[i][j])ma[i][j]=t2++; } for (i=1;i<=n;i++) for (j=1;j<=m;j++) if ((i+j)%2==0) { if (j>1&&a[i][j-1])f[ma[i][j]][ma[i][j-1]]=1; if (i>1&&a[i-1][j])f[ma[i][j]][ma[i-1][j]]=1; if (i<n&&a[i+1][j])f[ma[i][j]][ma[i+1][j]]=1; if (j<m&&a[i][j+1])f[ma[i][j]][ma[i][j+1]]=1; } int ans=0; for (i=1;i<t2;i++) { memset(v,0,sizeof(v)); if (dfs(i))ans++; } if (ans%2==0)printf("ÒÒ\n");else printf("¼×\n"); } }
后面两题也很水,水题都过不了主要是分析的问题,分析问题太弱了- -
2107 这题主要是要控制好stack栈顶的进出,一般单调队列都需要注意这个问题,代码很容易理解
:
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int stack[1000005]; int a[1000005]; int c[1000005]; int main() { int n,i,top,k,x; scanf("%d",&n); for(i=1;i<=n;i++) { scanf("%d",&a[i]); } top=0; memset(stack,0,sizeof(stack)); memset(c,0,sizeof(c)); for(i=1;i<=n;i++) { while(top>0) { if(top>0&&stack[top]>=a[i])top--; else break; } if(top==0)c[i]=-1; else c[i]=stack[top]; top++; stack[top]=a[i]; } scanf("%d",&k); while(k--) { scanf("%d",&x); printf("%d\n",c[x]); } return 0; }
1109 这题其实找规律就行了,用了点动态规划的思想。好好学DP啊。。。
:
#include<iostream> #include<cstring> using namespace std; int dp[2][20]; int main() { int n,j,k; cin>>n>>k; int sum; memset(dp,0,sizeof(dp)); dp[0][1]=1; dp[1][1]=k-1; for(int i=2;i<=n-1;i++)//代表位置 { dp[1][i]=dp[1][i-1]+dp[0][i-1]; dp[0][i]=dp[1][i-1]; dp[1][i]*=k-1; dp[0][i]*=1; } sum=dp[0][n-1]+dp[1][n-1]; cout<<sum*(k-1)<<endl; return 0; }