首先是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;
}