crazy Rows 2009 Round2 A

来源:互联网 发布:公众平台源码搭建 编辑:程序博客网 时间:2024/05/22 12:03
/*crazy Rows 2009 Round2 A给定一个有0 1 组成的矩阵,只允许交换相邻的两行要把矩阵化为下三角矩阵(主对角线上方的元素都是0)最少需要交换几次?输入的矩阵保证总能化成下三角矩阵限制:N∈[1,100]time <=1S内存 <=65535KBEG:1 1 1 0         1 1 1 0                 1 0 0 01 1 0 0  ____>  1 1 0 0  _____>···· 1 1 0 01 1 0 0      >  1 0 0 0       >···· 1 1 0 01 0 0 0         1 1 0 0                 1 1 1 0  输入3001100010输出 2   (交换1 2 再交换2 3 )  解:  先说内存 65535KB->64MB  若用int有点浪费空间 不如用char存储矩阵  如果真的一个一个尝试 那么就有N!种 显然时间上不允许  所以我们先暂时考虑: 最后应该把哪一行交换到第一行,第一行应该为全0行或首元素为1其他为0的行而这一行可以交换到任意一行 当有多个满足条件的行时选择离第一行近的行对应的最终费用小因为只能交换相邻的两行假设:X1 X2 X3……Xn   其中X1的元素不应该在第一个位置而这n个元素只有 X2 X3的元素 可以在X1的位置那么若交换 X2 X1则需要一步 然后X3又和X1交换  共两步 得到 X2 X3 X1……若把X3交换到第一行    两步 X2再与X1交换一步  共三步 得到 X3 X2 X1……这两种情况来看 第二种可以看作是第一种移动完了之后 又交换了 X2 X3如果X1 X2 X3之间出现了多个不应该在第一个的元素 是一样的道理 你可能会想 在X1 X2 X3之间插入的元素 万一出现也适合第一个位置的怎么办 其实上述的X1 X2 X3 是有条件的筛选的  每两个之间没有可以当第一个位置的元素如果有 比如 X1 Xm X2 X3中 Xm也符合第一个位置那么 此时应该把 X1 Xm X2 分别当作上述情况的 X1 X2 X3 她们只是代号而已  这个地方懂了 也就明白 为什么当有多个满足条件的行时选择离第一行近的行交换 则对应的最终费用小了。  确定第一行之后就没必要再动它 对于之后的行可以进行相同的处理  每一行中的0 1 数量多少并不重要  重要的是 最后一个1的位置  若将最后的1的位置记录下来 有利于降低复杂度  代码:*/# include <stdio.h># include <stdlib.h># include <time.h># define MAX 60int Swep(int *Flagi,int *Flagj);//交换函数 返回1int main(){char JZ[MAX][MAX+1]={"\0"};//将字符数组初始化为0int i,j,N,Flag[MAX]={0},sum=0,TU;//Flagi记录第i行的最后一个1出现的位置/*****这两行之间的都是生成随即矩阵的 只需要输入行数就能得到随机的符合条件的矩阵********/char MM[MAX+2]={"\0"},SS,QQ[MAX];//这个地方和程序没关系 只是为了生成随机矩阵而设的变量    srand(time(NULL));for(i=0;i<MAX;i++)MM[i]=i+1;//生成矩阵行printf("输入N[1,%d]:",MAX);scanf("%d",&N);//输入矩阵的行数SS=rand()%N;    for(i=0;i<N;i++){while(!MM[SS])SS=rand()%N;QQ[i]=SS;MM[SS]=0;}    for(i=0;i<N;i++)for(j=0;j<=QQ[i];j++)JZ[i][j]=rand()%4>=1;//生成随机矩阵为了提高1的比重(rand()%6>1)printf("随机矩阵:\n");for(i=0;i<N;i++){for(j=0;j<N;j++)printf("%d",JZ[i][j]);printf("\n");}/*****这两行之间的都是生成随即矩阵的 只需要输入行数就能得到随机的符合条件的矩阵********/for(i=0;i<N;i++){Flag[i]=-1;//每一行先假设没有1的情况下Flagi为-1for(j=0;j<N;j++)if(JZ[i][j]) Flag[i]=j;//这样就记录完每行末尾1的位置}for(i=0;i<N;i++){TU=-1;//TU记录要移动到第i行的行for(j=i;j<N;j++)if(Flag[j]<=i)//一旦寻找到离i最近的行{TU=j;   //记录 并执行交换break;}for(j=TU;j>i;j--)//交换{sum+=Swep(&Flag[j],&Flag[j-1]);printf("交换%02d  %02d两行\n",j,j+1);//为了快速得到最终结果 可删掉这一行}}printf("至少需要移动%d次\n",sum);return 0;}int Swep(int *Flagi,int *Flagj){int temp=*Flagi;*Flagi=*Flagj;*Flagj=temp;return 1;}

2 0
原创粉丝点击