不知道开头说点什么就给你劈个叉吧。
  • C - 开关问题

题意:http://poj.org/problem?id=1830
一开始拿深搜加状压刚果然超时了,,,看网上直接深搜都可以过怕是假的吧,,,有时间要再学一下计算复杂度了。
通过这个题复习了线代,高斯消元求解线性方程组。
use[1]表示开关1 relate[1][2]表示开关1对灯2是否有影响
u[1]*r[1][1]^u[2]*r[2][1]^u[3]*r[3][1]……^u[n]*r[n][1] = start[1]^end[1]
最后求出变元个数x,2^x即为答案。
//#include <bits/stdc++.h> #include<map> #include<set> #include<queue> #include<cmath> #include<stack> #include<ctime> #include<cstdio> #include<vector> #include<string> #include<sstream> #include<cstdlib> #include<cstring> #include<cassert> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int MAXN=1e5+10; #define pi   acos(-1.0) #define mod  1000000009 #define INF 0x3f3f3f3f3f #define endll printf("\n") #define s1(a) scanf("%d",&a) #define s2(a,b) scanf("%d %d",&a,&b) #define mem(a,b) memset(a,b,sizeof(a)) #define s3(a,b,c) scanf("%d %d %d",&a,&b,&c) //高斯消元 int n; int relate[30][30]; void input() {     s1(n);     mem(relate,0);     for(int i=0;i<n;s1(relate[i++][n]));     for(int i=0;i<n;i++)     {         relate[i][i]=1;         int x;s1(x);         relate[i][n]^=x;
}     int I,J;     while(s2(I,J)&&(I+J))         relate[J-1][I-1]=1; } int guess(int n,int m) {     int i=0,j=0;//目前处理到哪一行     int r;//找到j列第一个不为零的元素所在行     while(i<n&&j<m)     {         //生成阶梯矩阵         for(r=i;r<n;r++)             if(relate[r][j]) break;         if(r<n)         {             for(int k=0;k<=m;k++)                 swap(relate[r][k],relate[i][k]);             //开始消元             for(int k=i+1;k<n;k++)             {                 if(!relate[k][j]) continue;                 for(int c=j;c<=m;c++)                     relate[k][c]^=relate[i][c];             }             i++;         }         j++;     }     //计算最后自由变元个数     for(int k=i;k<n;k++)         if(relate[k][m]) return -1;     return 1<<(n-i); } int main() {     int t;s1(t);     while(t--)     {         input();         int ans=guess(n,n);         if(ans==-1) printf("Oh,it's impossible~!!\n");         else printf("%d\n",ans);     }     return 0; }
  • G - Tunnels 

天啊好不容易码好文我一手骚操作居然删了我哭了,,,,
再写一遍。。。
旅行商问题:
某点出发,要经过n个点,最后回到起点,求最短距离。
这个问题就是最短路的变形,只不过不要求回到起点,所以dp[i][0](集合为空集的情况)初始化为0,而不是dis[i][起点]。
还有一点就是需要进行预处理,将隧道缩点,dis[i][j]代表 i隧道尾部到达j隧道头部的距离。
注意dp初始化,然后顺推就行,根据图理解状态转移。

AC代码:
//#include <bits/stdc++.h>
#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<stack>
#include<ctime>
#include<cstdio>
#include<vector>
#include<string>
#include<sstream>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=1e5+10;
#define pi    acos(-1.0)
#define INF 0x3f3f3f3f
#define mod   1000000009
#define endll printf("\n")
#define s1(a) scanf("%d",&a)
#define s2(a,b) scanf("%d %d",&a,&b)
#define mem(a,b) memset(a,b,sizeof(a))
#define s3(a,b,c) scanf("%d %d %d",&a,&b,&c)
int n,m;
char s[20][20];//存图
struct IN
{
    int a,b,c,d;
}tun[20];
int dis[20][20];//一个隧道尾到另一个隧道头的最短距离
int dp[20][1<<16];
int dx[4]={1,-1,0,0};
int dy[4]={0,0,-1,1};
vector<int>state[20][20];//起点编号
int ok(int x,int y)
{
    if(x<1||x>n||y<1||y>n)
        return 0;
    if(s[x][y]=='#')
        return 0;
    return 1;
}
void bfs(int x)//state编号
{
    int d[20][20];
    mem(d,-1);
    queue<int>q;
    q.push((tun[x].c-1)*n+(tun[x].d-1));
    d[tun[x].c][tun[x].d]=0;
    while(!q.empty())
    {
        int xx=q.front();q.pop();
        int yy=xx%n+1;
        xx=xx/n+1;
        if(state[xx][yy].size())
        {
            int len=state[xx][yy].size();
            for(int i=0;i<len;i++)
                dis[x][state[xx][yy][i]]=d[xx][yy];
        }
        for(int i=0;i<4;i++)
        {
            int nx=xx+dx[i],ny=yy+dy[i];
            if(!ok(nx,ny)||d[nx][ny]!=-1) continue;
            d[nx][ny]=d[xx][yy]+1;
            q.push((nx-1)*n+ny-1);
        }
    }
}
int main()
{
    while(~s2(n,m))
    {
        mem(dis,0x3f);
        for(int i=0;i<=n;i++)
        {
            for(int j=0;j<=n;j++)
                state[i][j].clear();
        }
        for(int i=1;i<=n;i++)
            scanf("%s",s[i]+1);
        for(int i=0;i<m;i++)
        {
            scanf("%d %d %d %d",&tun[i].a,&tun[i].b,&tun[i].c,&tun[i].d);
            state[tun[i].a][tun[i].b].push_back(i);
        }
        for(int i=0;i<m;i++)
            bfs(i);
        int all=(1<<m);
        for(int i=0;i<=m;i++)
        {
            for(int j=0;j<=all;j++)
            {
                dp[i][j]=(j==0?0:INF);//j代表此状态要走过的点
            }
        }
        //  d(0,{1,2,3})=min{C01+d(1,{2,3}),C02+d{2,{1,3}},C03+d{3,{1,2}}}
        for(int s=1;s<all-1;s++)//枚举u的状态
        {
            for(int u=0;u<m;u++)
            {
                if(s&(1<<u)) continue;
                for(int v=0;v<m;v++)
                        if((s&(1<<v)))//保证v在u要走的集合中
                            dp[u][s]=min(dp[u][s],dp[v][s^(1<<v)]+dis[u][v]);
            }
        }
        int ans=INF;
        for(int i=0;i<m;i++)
            ans=min(ans,dp[i][(all-1)^(1<<i)]);
        printf("%d\n",ans==INF?-1:ans);
    }
    return 0;
}