您的位置:首页 > 其它

Codeforces Round #228 (Div. 2) D - Fox and Minimal path

2014-02-09 01:59 417 查看
前三题 没有什么可以说的 水题, 但是 B题 大意了,最后WA了,所以 rating 大降 T_T. 

何时才能进DIV1 啊。 

D题, 当时 交了一发,不过被HACK了,因为考虑不全面。 当时的想法是把 K 分解为1000 内的因数相乘 而且 这些因数的和<=1000。这样显然是不正确的,因为可能根本找不到这些符合条件的因数。

之后,考虑分解为二进制,之后是相乘之积 相加。上面的错误之处也就是在于全是相乘。

用这个思路分解,比如用二进制分解  K=5, 可以这么构造k=5=2*2+1*1;



 又在赛后写了一发, 在一个28个1的二进制的数上过不去, 经过计算,这样的构造方法会使节点的数目超过1000.   

所以考虑其他进制的分解,可以粗略算得  十进制的构造方法最糟不会超过800多节点,故可行。 10进制的方法和二进制思路一样。

code:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 1000000000
#define N 1005
int n,k;
bool vis

;
char s[100];
int main()
{
    scanf("%d",&k);
    sprintf(s,"%d",k);
    int len=strlen(s);
    memset(vis,0,sizeof(vis));
    int now=2,last;
    for(int i=0;i<len;i++)
    {
        int tmp=s[i]-'0';
        if(!tmp) continue;
        for(int j=1;j<=tmp;j++)
        {
            vis[1][now+j]=vis[now+j][1]=1;
        }
        last=now;
        now+=tmp;
        int need=len-i-1;
        for(int j=1;j<=need;j++)
        {
            last=now;
            if(j==1)
            {
                for(int p=now-tmp+1;p<=now;p++)
                    for(int q=now+1;q<=now+10;q++)
                        vis[p][q]=vis[q][p]=1;
            }
            else
            {
                for(int p=now-9;p<=now;p++)
                    for(int q=now+1;q<=now+10;q++)
                        vis[p][q]=vis[q][p]=1;
            }
            now+=10;
        }
        if(i==0)
        {
            for(int q=last+1;q<=now;q++)  vis[q][2]=vis[2][q]=1;
        }
        for(int j=1;j<=i;j++)
        {
            if(j==1)
            {
                for(int p=last+1;p<=now;p++) vis[p][now+1]=vis[now+1][p]=1;
                now++;
            }
            else
            {
                vis[now][now+1]=vis[now+1][now]=1;
                now++;
            }
            if(j==i) vis[now][2]=vis[2][now]=1;
        }
    }
    printf("%d\n",now);
    for(int i=1;i<=now;i++)
    {
        for(int j=1;j<=now;j++)
        {
            if(vis[i][j]) printf("Y");
            else printf("N");
        }
        puts("");
    }
    return 0;
}

 ----------------------------------------------------------------------------------------------------------------------------------

额 , 发现 二进制分解构造 是可行的 , 而且 结果会更优 , 不会超过100 个点的。

比如 , K=12;  1110(二进制)



除去 1  2 两点 分为 3层,列数决定于 二进制的位数,前2层构造完成,就构造出了最高位的方案数 样例中的8种。 再构造出 4+2 种就完成了。

就如图,连接红色的边,就完成了。  如果需要1种,就把 1 点 和左下角的点连接即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 1000000000
#define N 1005
int k,n;
bool vis

;
int m
,ad,mark,now=2;
void sol()
{
if(mark==0)
{
vis[1][2]=vis[2][1]=1; return ;
}
vis[1][4]=vis[1][5]=vis[4][1]=vis[5][1]=1;
for(int i=2;i<=mark;i++)
{
vis[i*3+1][i*3-2]=vis[i*3-2][i*3+1]=vis[i*3+2][i*3-1]=vis[i*3-1][i*3+2]=1;
vis[i*3+2][i*3-2]=vis[i*3-2][i*3+2]=vis[i*3+1][3*i-1]=vis[i*3-1][i*3+1]=1;
vis[i*3][i*3-3]=vis[i*3-3][i*3]=1;
}
vis[mark*3][2]=vis[2][mark*3]=vis[mark*3+1][2]=vis[2][mark*3+1]=vis[mark*3+2][2]=vis[2][mark*3+2]=1;
for(int i=0;i<mark;i++)
{
if(m[i] & (!i) )
{
vis[1][3]=vis[3][1]=1; continue;
}
if(m[i]) vis[3*i+3][3*i+1]=vis[3*i+1][3*i+3]=vis[3*i+3][3*i+2]=vis[3*i+2][3*i+3]=1;
}
now+=mark*3;
}
int main()
{
scanf("%d",&k);
memset(vis,0,sizeof(vis));
ad=-1;
for(int i=0;i<=31;i++)
{
int tmp=(k>>i)&1;
m[++ad]=tmp;
}

for(int i=32;i>=0;i--)
{
if(m[i])
{
mark=i; break;
}
}
sol();
printf("%d\n",now);
for(int i=1;i<=now;i++)
{
for(int j=1;j<=now;j++)
{
printf("%c",vis[i][j]==1? 'Y':'N');
}
puts("");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: