炮兵阵地(acm.pku1185)解法

炮兵阵地(acm.pku1185)解法与状态DP原理
 
# include <stdio.h>
# include <malloc.h>
void Input(char*,int,int);
void SetSolder(char*,int,int);
void InitChoice(int*,char*,int,int);
void FindBestPlace(int*,int,int,int);
int Calculate(int*,int,int,int);
void Connect(int*,int,int*,int,int);
int main(int argc,char* argv[]){
char *Map;//Map为地图数组
int n,m;//n代表地图的高,m代表地图的宽
printf("请输入地图的高度及宽度; ");
scanf("%d %d",&n,&m);getchar();
Map=(char*)malloc((n*m)*sizeof(char));
printf("\n绘制地图,h表示山,p表示平原:\n");
Input(Map,n,m);
SetSolder(Map,n,m);
free(Map);
return 1;
}
void Input(char* Map,int n,int m){
//用来对地图进行输入
int i,j;
printf("\n每行%d个字符,共计%d行\n",m,n);
 for(j=0;j<n;++j){
for(i=0;i<m;++i)
Map[j*m+i]=getchar();
 getchar();
}

}
void SetSolder(char *Map,int n,int m){
//在平原上进行设置炮兵的函数,也是本程序的关键
int *Choice,pi,num;//choice为选择数组名,平原初值为-1,在次平原上放炮兵其值为1,确定不在上放炮兵时为0
Choice=(int*)malloc((n*m)*sizeof(int));
InitChoice(Choice,Map,n,m);
for(pi=0;pi<n*m;++pi)
if(Choice[pi]==-1)
FindBestPlace(Choice,pi,n,m);
for(pi=0,num=0;pi<n*m;++pi)
if(Choice[pi]==1) ++num;
printf("\n\n最多可放人数: %d\n",num);
free(Choice);
}
void InitChoice(int Choice[],char *Map,int n,int m){
//用来初始化选择数组int Choice[],大小由输入的n*m值确定
int pi;
for(pi=0;pi<n*m;++pi)
if(Map[pi]=='h') Choice[pi]=-2;
else Choice[pi]=-1;
}
void FindBestPlace(int* Choice,int pi,int n,int m){
//以平原pi为起点判断与之相连的平原选择哪一个
int place[9],minnum=0,cout,pj,k,curpios=pi;
minnum=Calculate(Choice,pi,n,m);
if(minnum==0) Choice[pi]=1;
else{
Connect(Choice,pi,place,n,m);
 for(k=1;k<=place[0];++k){
pj=place[k];
cout=Calculate(Choice,pj,n,m);
 if(cout<minnum){
curpios=pj;
minnum=cout;
}
}
if(curpios!=pi) Connect(Choice,curpios,place,n,m);
Choice[curpios]=1;
for(k=1;k<=place[0];++k){
pj=place[k];
Choice[pj]=0;
}
}
}
int Calculate(int* Choice,int pi,int n,int m){
//计算射程范围内平原个数
int num=0;
int upone=pi-m,uptow=pi-2*m,
downone=pi+m,downtow=pi+2*m,
leftone=pi-1,lefttow=pi-2,
rightone=pi+1,righttow=pi+2;
if(upone>=0&&Choice[upone]==-1) ++num;
if(uptow>=0&&Choice[uptow]==-1) ++num;
if(downone<n*m&&Choice[downone]==-1) ++num;
if(downtow<n*m&&Choice[downtow]==-1) ++num;
if(pi%m!=0&&Choice[leftone]==-1) ++num;
if(pi%m!=0&&leftone%m!=0&&Choice[lefttow]==-1) ++num;
if(rightone%m!=0&&Choice[rightone]==-1) ++num;
if((pi+1)%m!=0&&(rightone+1)%m!=0&&Choice[righttow]==-1) ++num;
return num;
}
void Connect(int* Choice,int pi,int* place,int n,int m){
//把相连的平原防入数组
int i=0,
 upone=pi-m,uptow=pi-2*m,
downone=pi+m,downtow=pi+2*m,
leftone=pi-1,lefttow=pi-2,
rightone=pi+1,righttow=pi+2;
 if(upone>=0&&Choice[upone]==-1) place[++i]=upone;
if(uptow>=0&&Choice[uptow]==-1) place[++i]=uptow;
if(downone<n*m&&Choice[downone]==-1) place[++i]=downone;
if(downtow<n*m&&Choice[downtow]==-1) place[++i]=downtow;
if(pi%m!=0&&Choice[leftone]==-1) place[++i]=leftone;
if(pi%m!=0&&leftone%m!=0&&Choice[lefttow]==-1) place[++i]=lefttow;
if(rightone%m!=0&&Choice[rightone]==-1) place[++i]=rightone;
if((pi+1)%m!=0&&(rightone+1)%m!=0&&Choice[righttow]==-1) place[++i]=righttow;
 place[0]=i;
}





 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值