2011.08.17

POJ  3678  Katu Puzzle

        题意:有n个位置可以填0和1,给出m个逻辑表达式描述了zhi[a] op zhi[b]=c的关系,给出a,b,c,op。其中ai,bi,ci是0或1,op是逻辑运算符AND,OR和XOR。问是否有一个n元素的数组zhi[ ]可以满足全部m个表达式。有则输出"YES",否则输出"NO"。

        解题:相当标准的2-SAT问题。重点是理解2-SAT的建图主要是根据矛盾则向矛盾的另一方连边,以及对偶边,而不管当前取值是否也与另一方矛盾。

#include<cstdio>
#include<cstring>
#include<string>
#include<fstream>
#define MV 1005
#define ME 1000005
using namespace std;
struct edge
{
    int v,next;
}g[ME],gt[ME],tree[ME];
int n,m,cnt,ID,p1,p2,id[MV],tree_cnt,order[MV],indegree[MV],color[MV],h1[MV],h2[MV];
bool used[MV],used_tree[MV][MV];
void add(int u,int v)
{
    g[p1].v=v;
    g[p1].next=h1[u];
    h1[u]=p1++;

    g[p1].v=u^1;          //对偶边
    g[p1].next=h1[v^1];
    h1[v^1]=p1++;

    gt[p2].v=u;           //反向边
    gt[p2].next=h2[v];
    h2[v]=p2++;

    gt[p2].v=v^1;         //对偶边的反向边
    gt[p2].next=h2[u^1];
    h2[u^1]=p2++;
}

void init()
{
    p1=p2=1;
    memset(h1,-1,sizeof(h1));
    memset(h2,-1,sizeof(h2));
}

void build_graph()
{
    int a,b,c;
    string s;
    char op[10];
    scanf("%d%d",&n,&m);
    while(m--){
        scanf("%d %d %d %s\n",&a,&b,&c,op);
        s=op;
        if(s=="AND" && c==1){
            add(2*a,2*b);
            add(2*a,2*b+1);
            add(2*a+1,2*b+1);
        }
        else if(s=="AND" && c==0){
            add(2*a+1,2*b);
        }
        else if(s=="OR" && c==1){
            add(2*a,2*b+1);
        }
        else if(s=="OR" && c==0){
            add(2*a,2*b);
            add(2*a+1,2*b);
            add(2*a+1,2*b+1);
        }
        else if(s=="XOR" && c==1){
            add(2*a,2*b+1);
            add(2*a+1,2*b);
        }
        else if(s=="XOR" && c==0){
            add(2*a,2*b);
            add(2*a+1,2*b+1);
        }
    }
}

void dfs1(int u)
{
    used[u]=1;
    for(int i=h1[u];i!=-1;i=g[i].next)
        if(!used[g[i].v])
            dfs1(g[i].v);
    order[cnt++]=u;
}

void dfs2(int u)
{
    used[u]=1;
    id[u]=ID;
    for(int i=h2[u];i!=-1;i=gt[i].next)
        if(!used[gt[i].v])
            dfs2(gt[i].v);
}

void scc()
{
    memset(used,0,sizeof(used));
    cnt=0;
    for(int i=0;i<2*n;i++)
        if(!used[i]) dfs1(i);
    memset(used,0,sizeof(used));
    ID=0;
    for(int i=cnt-1;i>=0;i--)
        if(!used[order[i]]){
            ID++;
            dfs2(order[i]);
        }
}

bool sat_judge()
{
    for(int i=0;i<2*n;i+=2)
        if(id[i]==id[i+1])
            return 0;
    return 1;
}

int main()
{
    init();
    build_graph();
    scc();
    if(sat_judge()) printf("YES\n");
    else printf("NO\n");
    return 0;
}



HDU  3940  The Angry  Birds  

        题意:

#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<fstream>
using namespace std;
const double g=9.8;
double h;
char c[10];
string s;

void red()
{
    double vx,vy,s;
    scanf("%lf%lf",&vx,&vy);
    s=vx*(vy/g+sqrt(2*h/g+vy*vy/g/g));
    printf("%.3lf\n",s);
}

void yellow()
{
    double vx,vy,s,t1,t2,t3,t,h1,h2;
    scanf("%lf%lf%lf",&vx,&vy,&t);
    t1=vy/g;
    t2=sqrt(2*(h+vy*vy/2/g)/g);
    if(t1+t2<t){
        printf("%.3lf\n",vx*(vy/g+sqrt(2*h/g+vy*vy/g/g)));
        return ;
    }
    else if(t<t1){
        h1=vy*t-g*t*t/2;
        vy=2*(vy-g*t);
        t1=vy/g;
        h2=g*t1*t1/2;
        t2=sqrt(2*(h+h1+h2)/g);
        s=vx*(t+2*(t1+t2));
    }
    else{
        h1=vy*t-g*t*t/2+h;
        vy=2*g*t-2*vy;
        t3=(vy-sqrt(vy*vy+2*g*h1))/(-g);
        s=vx*(t+2*t3);
    }
    printf("%.3lf\n",s);
}

void blue()
{
    double vx,vy,t,t1,t2,s[3],v[3];
    scanf("%lf%lf%lf%lf%lf%lf",&vx,&vy,&t,&v[0],&v[1],&v[2]);
    t1=vy/g;
    t2=sqrt(2*(h+vy*vy/2/g)/g);
    if(t1+t2-t<0){
        printf("%.3lf\n",vx*(vy/g+sqrt(2*h/g+vy*vy/g/g)));
        return ;
    }
    for(int i=0;i<3;i++)
        s[i]=vx*t+(t1+t2-t)*v[i];
    printf("%.3lf %.3lf %.3lf\n",s[0],s[1],s[2]);
}

int  main()
{
    while(scanf("%lf %s",&h,c)!=EOF){
        s=c;
        if(s=="Red") red();
        else if(s=="Blue") blue();
        else yellow();
    }
    return 0;
}




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值