HDU4121 Xiangqi

只有四种棋子:将、车、马、炮,黑方只有一个将,现在被红方将,红方有2至7个棋子,判断黑方是否被将死。

考虑黑将的四个行动方向,判断每个位置是否被将死即可。

将:判断两个将之间是否有棋子
车:同上
马:八个方向,容易出错,详见代码
炮:将与炮之间是否只有一个棋子

//不考虑黑方飞将也能过,不知道到底该不该考虑。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
struct point
{
    int x,y;
}g[10], r[10], h[10], c[10]; //bg:black general
int gcount, rcount, hcount, ccount;
const int dx[] = {-1, 0, 1, 0};
const int dy[] = {0, 1, 0, -1};
 
const int hx[] = {-2, -2, -1, 1, 2, 2, 1, -1};
const int hy[] = {1, -1, 2, 2, 1, -1, -2, -2};
bool map[10][10]; //红旗子
 
//将是否在范围内
bool isValid(int x, int y)
{
    return y >= 4 && y <= 6 && x >= 1 && x <= 3;
}
 
//[a,y]到[b,y]的棋子个数(不含端点)
int betweenX(int y, int a, int b)
{
    int sum = 0;
    if (a < b)
    {
        for (int i = a + 1; i < b; i++)
        {
            if (map[i][y]) sum++;
        }
    }
    else
    {
        for (int i = b + 1; i < a; i++)
        {
            if (map[i][y]) sum++;
        }
    }
    return sum;
}
 
//[x,a]到[x,b]的棋子个数(不含端点)
int betweenY(int x, int a, int b)
{
    int sum = 0;
    if (a < b)
    {
        for (int i = a + 1; i < b; i++)
        {
            if (map[x][i]) sum++;
        }
    }
    else
    {
        for (int i = b + 1; i < a; i++)
        {
            if (map[x][i]) sum++;
        }
    }
    return sum;
}
 
//将的新位置newbg是否会被红方飞将
bool isSafeGeneral(point const &newbg)
{
    //其实只有一个嘛
    for (int i = 0; i < gcount; i++)
    {
        if (newbg.y == g[i].y)
        {
            if (betweenX(newbg.y, newbg.x, g[i].x) == 0) return false;
        }
    }
    return true;
}
 
//是否会被车吃(中间没有其他棋子)
bool isSafeChariot(point const &newbg)
{
    for (int i = 0; i < rcount; i++)
    {
        if (newbg.x == r[i].x && newbg.y == r[i].y) continue; //这就是吃掉了
        if (newbg.x == r[i].x)
        {
            if (betweenY(newbg.x, newbg.y, r[i].y) == 0) return false;
        }
        if (newbg.y == r[i].y)
        {
            if (betweenX(newbg.y, newbg.x, r[i].x) == 0) return false;
        }
    }
    return true;
}
 
//是否会被炮打(中间棋子为1)
bool isSafeCannon(point const &newbg)
{
    for (int i = 0; i < ccount; i++)
    {
        if (newbg.x == c[i].x && newbg.y == c[i].y) continue; //这就是吃掉了
        if (newbg.x == c[i].x)
        {
            if (betweenY(newbg.x, newbg.y, c[i].y) == 1) return false;
        }
        if (newbg.y == c[i].y)
        {
            if (betweenX(newbg.y, newbg.x, c[i].x) == 1) return false;
        }
    }
    return true;
}
 
bool isSafeHorse(point const &newbg)
{
    int newx, newy;
    for (int i = 0; i < hcount; i++)
    {
        for (int j = 0; j < 8; j++)
        {
            newx = h[i].x + dx[j / 2];
            newy = h[i].y + dy[j / 2];
            if (map[newx][newy]) continue; //别马腿
            newx = h[i].x + hx[j];
            newy = h[i].y + hy[j];
            if (newx == newbg.x && newy == newbg.y) return false;
        }
    }
    return true;
}
 
//如果不被将,返回真
bool check(point const &newbg)
{
    return isSafeGeneral(newbg) && isSafeCannon(newbg) && isSafeHorse(newbg) && isSafeChariot(newbg);
}
 
int main()
{
    int n;
    char ch;
    int a, b;
    while (true)
    {
        point bg, newbg; //bg:black general
        gcount = 0, rcount = 0, hcount = 0, ccount = 0;
        memset(map, 0, sizeof(map));
        bool checkmate = true;
        cin >> n >> bg.x >> bg.y;
        if (!n) break;
        for (int i = 0; i < n; i++)
        {
            cin >> ch >> a >> b;
            map[a][b] = true;
            if (ch == 'G')
            {
                g[gcount].x = a;
                g[gcount].y = b;
                gcount++;
            } else
            if (ch == 'R')
            {
                r[rcount].x = a;
                r[rcount].y = b;
                rcount++;
            } else
            if (ch == 'H')
            {
                h[hcount].x = a;
                h[hcount].y = b;
                hcount++;
            } else
            if (ch == 'C')
            {
                c[ccount].x = a;
                c[ccount].y = b;
                ccount++;
            }
        }
        //不考虑飞将也能过
        /*
        if (!isSafeGeneral(bg))
        {
            puts("NO");
            continue;
        }
        */
        //将的四个方向
        for (int i = 0; i < 4; i++)
        {
            newbg.x = bg.x + dx[i];
            newbg.y = bg.y + dy[i];
            if (!isValid(newbg.x, newbg.y)) continue;
            if (check(newbg))
            {
                checkmate = false;
                break;
            }
        }
        if (checkmate) puts("YES");
        else puts("NO");
    }
    return 0;
}

敲代码的时候曾经把g、r、h、c数组弄混过。。以后这种题还是用拼音算了。
测了样例和马的情况就交了。
第一次WA错在puts里面写了\n…
又测了几个数据都正常,然后看了一遍代码,还是没发现错误。
试了黑棋直接飞将,还是WA,看别人题解突然想到我还考虑将走斜线的情况了。。
最后,似乎是否考虑黑棋直接飞将都可以。

这题我没着急慢慢写的,如果现场的话至少两小时吧,很有可能有个小错找不出来,不确定到底能不能写好。
还是边写边想,还好没犯大错误,betweenX等是写了很多之后才想到单独写个函数的。。

只有两周了,时间好紧张= =

2012新年快乐

新年快乐~

2011这一年,收获很多。学到了很多东西、转了专业、去了两次ACM现场赛打酱油等等等等

每天都过得很充实。晚上写日记回顾一天的时候常常感觉早上的事是很久以前发生的。现在差不多在OhLife上记了365篇日记了~

希望明年每天都开开心心的,假期好好玩、好好学。参加更多的活动,让生活更精彩~

期末考加油,另外希望明天买到火车票。

用字符数组存int

EUYUIL告诉我可以用字符数组存int。挺好玩。

unsigned char test[100];
memset(test, 0, sizeof(test));
int a = 2147483647;
int *p = (int*)&test;
*p = a;
int b = *p;
cout << b << endl;

此时test数组为{255, 255, 255, 127, 0…}
当然,如果a是1的话,test就是{1, 0, 0, 0, 0…}
这是VS2010编译的结果。。不知道其他编译器其他平台结果怎么样。。

刚刚在stackoverflow搜到这个问题,以后有空再看看吧。

总感觉我C++好弱,指针几乎没用过= =

Update @ 2011/12/13 23:39
如果放入TCHAR里,就是{65535, 32767, …}。

20111101

这么就十一月了,这学期过得好快啊。

转到软院也没什么特别的感觉。。本来以为这学期会比较轻松比较爽,只是英语交流有点烦人,不过极少数情况下背课文会背到很开心。。特别是在机房…
PS:换了新键盘打字爽多了!

写着到这里都忘了想说啥…囧

感觉现在还是在铜牌和铁牌的边缘= =

概率课又是听不进去…还不如不去呢..期中考怎么办。
OS期中项目挑了个简单的写,自学GUI神马的,写完之后一点成就感都没有,就是一种码农的感觉…
Win程还没开始写,得到deadline再说吧= = 到时候得疯狂一阵,看起来比Java难写多了。
周四英语期中演讲说点啥呢,周四翻了半天Read it later的收藏(顺便整理一下)也没想好,本来想说C语言之父什么的,想想还是算了吧,还是说火车迷吧。

老妈刚才问我看没看F1,才想到都好久没看直播了。火星车还是这么猛= = 大一还加了个F1车迷协会,曾经想过买个方向盘玩F1呢。

福州完了之后好好学英语、好好学数学、好好敲代码。。以后TopCoder之类的比赛多写写吧…

一会把北京A题敲了吧…

数据结构有两节课没听了吧…明天上课的时候看看以前讲的PPT吧。

PS:不喜欢GR和Gmail的新版!字怎么这么大

ICPC 2011

随便写个标题吧。。算不算标题党? 整理一下最近写的题目。

大连网络赛
To Miss Our Children Time
背包问题,排个序就行了,题目描述不清。。

Find Metal Mineral
树形动归,f[x][j]表示以x为根的树,前i个子树放j个机器人不回来的最小值,DFS的感觉。f[x][0]表示放一个再出来。做的第一个树形动归,参照别人的代码,很巧妙的写法嘛。刚才看题目忘了具体怎么写了= =

void work(int x,int prev)
{
    for (int i=head[x];i!=-1;i=edge[i].next)
    {
        if (edge[i].y==prev) continue;
        work(edge[i].y,x);
        for (int j=k;j>=0;j--)
        {
            f[x][j]+=f[edge[i].y][0]+edge[i].w*2;
            for (int l=0;l<j;l++)
            f[x][j]=min(f[x][j],f[x][l]+edge[i].w*(j-l)+f[edge[i].y][j-l]);
        }
    }
}

PS:原来这个叫做分组背包= =

The Frog’s Games
比赛的时候以为是DP,结果就是个二分…

The kth great number
最简单的办法就是弄一个最小堆,堆顶就是答案,priority_queue用起来很爽。

priority_queue <int, vector<int>, greater<int> > heap;
 
if (heap.size()<k) heap.push(temp);
else if (temp>heap.top())
    {
        heap.pop();
        heap.push(temp);
    }

还可以写个treap..treap的删除还不会写= =

Dave
注意正方形的顶点不一定是题中的点。
把点分别按x和y排序,四条线扫描,写得比较乱= =

The 36th ACM/ICPC Asia Regional Shanghai Site —— Warmup
Working in Beijing
Parsing URL
两道水题,第一题题目说明不清楚= = 做做调节心情

上海网络赛
24 Puzzle
如果空位在角上则挪到中间的正方形里,然后比较8个角是否相同,相同才有可能有解。对于4*4,左右交换不改变逆序对,上下交换时逆序数的奇偶性改变一次(0-3,3-0,1-2,2-1)。
http://zhyu.me/acm/hdu-4021.html
觉得这个证明不完备,没想好怎么证。

Bombing
multiset真的很爽…

typedef map<int, multiset<int> > dict;
 
void work(dict &a, dict &b, int &x)  //delete a(x) from b
{
    printf("%d\n",a[x].size());
    for (multiset<int>::iterator iter=a[x].begin();iter!=a[x].end();iter++)
    {
        b[*iter].erase(x);
    }
    a[x].clear();
}
 
int main()
{
    int n,m,x,y;
    while (scanf("%d%d",&n,&m)!=EOF)
    {
        if (n==0 && m==0) break;
        dict a,b;
        for (int i=0;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            a[x].insert(y);
            b[y].insert(x);
        }
        for (int i=0;i<m;i++)
        {
            scanf("%d%d",&x,&y);
            if (x==0) work(a,b,y);
            else work(b,a,y);
        }
        printf("\n");
    }
    return 0;
}

Game
比较简单的博弈问题,比赛的时候没静下心来想。
分组讨论,注意一个细节,9、10如果竖着的放好了,对方就不用抢这种了。

成都网络赛
Graph
给最短边求原图,原来可以这样写

void work(const int n)
{
    for (int k=0;k<n;k++)
    for (int i=0;i<n;i++)
    for (int j=0;j<n;j++)
    {
        if (i==j || i==k || k==j) continue;
        if ((!visited[i][j]) && map[i][k]+map[k][j]==map[i][j])
        {
            ++c;
            visited[i][j]=true;
        }
    }
}
printf("%d\n",n*(n-1)-c);

Rolling Hongshu
物理题,考虑顶点和所有bitter potato。题目描述挺好玩…

The Social Network
第一次用map。

map<string,int> num;

读入:

cin>>s1>>s2;
if (num.count(s1)) n1=num.find(s1)->second;
else
    {
        num.insert(make_pair(s1, ++count));
        n1=count;
        sn[n1]=s1;
    }
if (num.count(s2)) n2=num.find(s2)->second;
else
    {
        num.insert(make_pair(s2, ++count));
        n2=count;
        sn[n2]=s2;
    }
f[n1][++f[n1][0]]=n2;//f[n1]存n1的朋友们
f[n2][++f[n2][0]]=n1;

接下来就慢慢弄吧…

北京网络赛
Eliminate Witches!
模拟,递归处理,WA好几次= =
不过这个是我在今年网络赛时作出的第一道题= =

Panda
树状数组。a[i]表示以i开头的是不是wbw。自己没想到这种方法。

if (s[i]=='w' && s[i+1]=='b' && s[i+2]=='w') add(i,1);

Tourism Planning
第一个状态压缩DP,把某人去不去用二进制表示。
f[15][1030];//f[i][j]前i个景点,第j个状态的最大值
预处理当前状态能由哪些状态得到,如果不预处理HDU可以很快AC,BOJ会TLE= =

wolf5x
概率DP。
比赛时就想对了方法,读题不认真,以为第一步左右概率相同呢。
赛后写好,发现还是看错题了,以为是求停止位置,原来是求步数的期望,可以直接把所有状态的概率加起来!

int main()
{
    int t;
    int n,a,b;
    int i,j;
    double ans;
    double p[2010][4];
    double f[2010][4];
    double temp1,temp2,temp3;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d%d%d",&n,&a,&b);
        ans=0;
        for (i=1;i<=n;i++) scanf("%lf%lf%lf%lf",&p[i][0],&p[i][1],&p[i][2],&p[i][3]);
        memset(f,0,sizeof(f));
        temp1=1;
        for (i=a;i<=b;i++)
        {
            if (i>n)
            {
                ans+=temp1;
                break;
            }
            for (j=1;j<=3;j++) f[i][j]=temp1*p[i][j];
            temp1*=p[i][0];
        }
        for (i=a;i<=n;i++)
        {
            temp1=temp2=temp3=1;
            for (j=i+a;j<=i+b;j++)
            {
                if (j>n)
                {
                    ans+=f[i][1]*temp1+f[i][2]*temp2+f[i][3]*temp3;
                    break;
                }
                else
                {
                    f[j][1]+=(f[i][2]*temp2+f[i][3]*temp3)*p[j][1]; //表示以这种状态踩在j
                    f[j][2]+=(f[i][1]*temp1+f[i][3]*temp3)*p[j][2];
                    f[j][3]+=(f[i][1]*temp1+f[i][2]*temp2+f[i][3]*temp3)*p[j][3];
                    temp1*=p[j][0]+p[j][1];  //tempi表示f[prev][i]不能走的概率
                    temp2*=p[j][0]+p[j][2];
                    temp3*=p[j][0];
                }
            }
            ans+=f[i][1]+f[i][2]+f[i][3];
        }
        printf("%.8lf\n",ans);
    }
    return 0;
}

大连现场赛
The Last Puzzle
对于任意一段,都是从任意一端开始到中间,因为如果从中间开始,还是要先到两端再到最终节点。想通了这个就很好写了。
f[i][j][k]表示从i到j这一段,k表示从左或从右开始,所需的最短时间。不可能则记为-1。

Hexadecimal View
水题,不知道可以用 %x 输出…

Number String
f[i][j]存当前所有可能情况,即i=n时只有f[n][1]。表示字符串中第i位是,表中第j个有几种情况。f[i+1]保存的数量比f[i]少一个,因为有一个数字被选走了。

for (i=1;i<=n;i++) f[1][i]=1;
for (int ii=0;ii<n;ii++)
{
    i=ii+2;
    if (str[ii]=='I')
    {
        f[i][1]=f[i-1][1];
        for (j=2;j<=n-i+1;j++) f[i][j]=(f[i-1][j]+f[i][j-1])%MOD;
    }
    else if (str[ii]=='D')
    {
        f[i][n-i+1]=f[i-1][n-i+2];
        for (j=n-i;j>=1;j--) f[i][j]=(f[i-1][j+1]+f[i][j+1])%MOD;
    }
    else
    {
        sum=0;
        for (j=1;j<=n-i+2;j++) sum=(sum+f[i-1][j])%MOD;
        for (j=1;j<=n-i+1;j++) f[i][j]=sum;
    }
}
printf("%d\n",f[n][1]);

福州网络赛
SanguoSHA
当时不爽,写这题写了好久= = 最后写好了觉得会WA,于是没交,回宿舍交了发现过了。
STL里居然有全排列… next_permutationprev_permutation

===
仔细想想有些题还是可以做的,并不是不会算法,而是想不到。另外数学太烂了。

大二,作业没大一多了,更加觉得时间不够用。平时训练做题效率很低。还有好多想学的东西呢。

2011暑假做的ACM题目

去了北大那个暑期课程… 对于我来说还是难了点,我觉得还不如自己看PPT= =。早知道能找得到10年的PPT就预习一下了。。
发现不会的好多,慢慢学吧。

部分题目:
8.7
HDU 3836 Equivalent Sets Tarjan强连通分量

8.8
POJ 1273 Drainage Ditches 最简单的网络流
POJ 3436 ACM Computer Factory 把机器拆成两个点求最大流
POJ 2112 Optimal Milking Floyd求最短路,然后二分答案,求最大流判断是否满足

8.9
POJ 1149 PIGS 建图不好想
POJ 2396 Budget 建图也不好想,有流量限制的最大流,用邻接矩阵写得很痛苦= =
//终于知道网络流是啥意思了。。感觉还得多做题
TopCoder SRM513 DIV2 第一题 这也算是我第一道TopCoder题

8.10
POJ 2135 Farm Tour 最小费用最大流,用SPFA选最短路增广
POJ 2318 TOYS
POJ 2398 Toy Storage 这两题是很简单的计算几何,用叉乘判断左右+二分
POJ 1113 Wall 做的第一个凸包,自己写的~

8.11
POJ 2349 Arctic Network 最小生成树,第一次写Prim…
TopCoder SRM512和513 DIV2 的前两题

8.12
POJ 1204 Word Puzzles Trie树,这东西太神奇了。。真快,(现在对KMP还不是很理解= =)

8.13
POJ 3987 Computer Virus on Planet Pandora Trie树
POJ 3691 DNA repair 在Trie树上DP,看了答案还想了很久

淘宝密码被盗

其实没什么好说的,就是淘宝密码被盗和绑定的手机被改,应该是在图书馆登录过一次支付宝。。现在觉得支付宝还是挺安全的,发现异地登录就自动关闭余额支付功能了。最开始我还以为和foursquare一样,把嘉定和上海误会成两个城市了。。一直用支付宝转账+提现来转生活费,这样节省手续费,以后更得注意安全了= =


我好像登录的就是支付宝。。而支付宝密码没有被改。


这是淘宝信息,这时间,显然不是我。。手机号也不对。


由于超时被关闭的交易

============

第一次感到丢失密码的可怕是看这个:http://www.storyday.com/html/y2008/1405_hutchison-lost-password-gmail.html

这是好办法:http://www.storyday.com/html/y2007/581_manage-your-password.html

============

1换什么密码好?想个自己记得住别人记不住的密码及安全问题很难啊。。而且不同网站密码最好不要相同,至少要保证找回密码邮箱的安全性,还不能忘了安全问题。最好还得大小写数字特殊符号。

2尽量不要使用公用电脑,这才是最重要的吧。在任何情况下我都不会在非本人电脑上登录gmail(好像去年9月初在网吧上过一次= =),现在看来。。其他的也不太安全,图书馆的电脑连进程都不能看= = 上人人的话问题不大吧。。不过要是日志被删也不爽呃,应该没人这样吧…记得删除cookies、浏览记录什么的。