今天写简述版题解。。。
第一道哦!
poj 1386
什么意思。。自行百度一下吧。
是个欧拉路经典题。
首先,我们把单词首尾建边。
这样就会出现一个图,而这个图必须联通的。这里我们就可以用并查集看是否联通,也可以用 dfs但是强烈 推荐并查集 因为 dfs不好判 是不是有很多棵树【【其实是因为po主沙茶,wa了一下午】】
然后我们就可以总结一下 欧拉路 的特点了 加深一下印象。
有向图:
欧拉回路:所有点满足入度=出度
欧拉路:所有点入度=出度//就是环的情况吗;或起点出度-入度=1,终点入度-出度=1,其余点入度=出度
无向图:
欧拉回路:所有点度数为偶数
欧拉路:至多两个点度数为奇数
贴个题解:
#include
#include
#include
#include
#include
#include
using namespace std;
#define sf scanf
#define pf printf
#define clr(xx) memset(xx,0,sizeof(xx)) //学会了,以后可以试试for
#define INF 1000000001
#define MIN -1000000001
int parent[30];
int in[30],out[30];
bool visited[30];
char s[1010];
int i,x,y,n;
int bingchaji(int x){
return parent[x]==x?x:bingchaji(parent[x]);
}
void init(int fx,int fy){
fx=bingchaji(x);
fy=bingchaji(y);
if(fx!=fy) parent[fx]=fy;
}
int main(){
int cas;
scanf("%d",&cas);
while(cas--){
clr(in);clr(out);clr(visited);
scanf("%d",&n);
gets(s);
for(i=0;i<26;i++)
parent[i]=i;
for(i=1;i<=n;i++){
scanf("%s",s);
int len=strlen(s)-1;
x=s[0]-'a';
y=s[len]-'a';
visited[x]=true;
visited[y]=true;
init(x,y);
in[x]++;
out[y]++;
}
for(i=0;i<26;i++)
if(visited[i])break;
x=bingchaji(i);
for(i=i+1;i<26;i++)
if(visited[i]&&x!=bingchaji(i))break;
if(i<26){
printf("The door cannot be opened.\n");
continue;
}
int count1=0;
int count2=0;
for(i=0;i<26;i++)
if(visited[i]){
if(in[i]!=out[i]) count1++;
if(in[i]-out[i]==1||out[i]-in[i]==1) count2++;
}
if(count1==0||(count1==2&&count2==2))
printf("Ordering is possible.\n");
else printf("The door cannot be opened.\n");
}
return 0;
}
#include
#include
#include
//by mars_ch
using namespace std;
int n;
int tot;
bool flag;
char a[1010];
int in[30],out[30];
int first[30];
int vis[30];
int v[30];
int f[200005],t[200005],nxt[200005];
void add(int a,int b)
{
f[tot]=a;
t[tot]=b;
nxt[tot]=first[a];
first[a]=tot++;
}
void dfs(int s)
{
for(int i=first[s];i!=-1;i=nxt[i])
{
if(v[t[i]] == 0) v[t[i]]=1,dfs(t[i]);
}
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(vis,2,sizeof(vis));
memset(first,-1,sizeof(first));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
tot=0;
flag=true;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",a);
int l=strlen(a);
add(a[0]-'a',a[l-1]-'a');
out[a[0]-'a']++;
in[a[l-1]-'a']++;
vis[a[0]-'a']=0;
vis[a[l-1]-'a']=0;
}
for(int i=0;i<26;i++)
{
if(vis[i]!=2)
{
for(int j=0;j<26;j++)
{
v[j]=vis[j];
}
flag=true;
v[i]=1;
dfs(i);
for(int j=0;j<26;j++)
{
if(v[j] == 0)
{
flag=false;
//printf("%d %d\n",i,j);
}
}
//printf("%d\n",flag);
if(flag == true) break;
}
}
int cnt1=0,cnt2=0,cnt3=0;
for(int i=0;i<26;i++)
{
if(in[i]!=out[i]) cnt3++;
if(in[i] == out[i]-1 ) cnt1++;
if(out[i] == in[i]-1) cnt2++;
}
//printf("%d\n",flag);
//printf("%d %d %d\n",cnt1,cnt2,cnt3);
if(flag==true &&(cnt3 == 0 ||(cnt3==2 &&cnt1==1 && cnt2==1)))
{
puts("Ordering is possible.");
}
else puts("The door cannot be opened.");
}
return 0;
}
第二道:
同上,就是提议很坑爹,输入也很坑爹。。
题目大意:
John有很多朋友住在不同的街,John想去访问每位朋友,同时希望走的路最少。因为道路很窄,John在一条路上不能往回走。John希望从家里出发,拜访完所有的朋友后回到自己的家,且总的路程最短。John意识到如果可以每条道路都只走一次然后返回起点应该是最短的路径。写一个程序帮助John找到这样的路径。给出的每条街连接两个路口,最多有1995条街,最多44个路口。街编号由1到n, 路口分别编号1到m.
输入:每个用例一个数据块:每行表示一条街,由三个整数组成:x,y,z. z为这条街的编号,x和y表示这条街连接的两个路口的编号。(实际数据中可能是自环).John住在一个输入块中第一行中连接的两个顶点中编号较小的路口处。所有的街都可以连通到其他街上。“0 0”表示一个数据块的结束。再一个0 0 表示输入的结束。
输出:如果能找到所有街道遍历一次的回路,输出找到的路径,如果不存在,输出“Round trip does not exist.”
#include
#include
#include
#include
//by mars_ch
using namespace std;
int map[50][2005];
int deg[105];
int tot;
int ori;
int cnt;
int vis[2005];
int q[2005];
void dfs(int a)
{
for(int i=1;i<=cnt;i++)
{
if(!vis[i] && map[a][i])
{
vis[i]=1;
dfs(map[a][i]);
q[tot++]=i;
}
}
}
int main()
{
int a,b,c;
while(1)
{
scanf("%d%d",&a,&b);
if(a == 0 && b == 0)
{
break;
}
scanf("%d",&c);
memset(map,0,sizeof(map));
memset(deg,0,sizeof(deg));
map[a][c]=b;
map[b][c]=a;
cnt=1;
tot=0;
ori=min(a,b);
deg[a]++;
deg[b]++;
while(1)
{
scanf("%d%d",&a,&b);
if(a == 0 && b == 0)
{
break;
}
scanf("%d",&c);
map[a][c]=b;
map[b][c]=a;
deg[a]++;
deg[b]++;
++cnt;
}
bool flag=true;
for(int i=1;i<=44;i++)
{
if(deg[i] % 2 !=0)
{
flag = false;
break;
}
}
if(flag==false)
{
puts("Round trip does not exist.");
continue;
}
memset(vis,0,sizeof(vis));
dfs(ori);
for(int i=tot-1;i>=0;i--) //反着的,回溯是一个过程
{
printf("%d ",q[i]);
}
puts("");
}
return 0;
}
第三道:
字典序+欧拉 但是字典序 真的是照着抄的。。。算是第二编写了吧
#include
#include
using namespace std;
#define maxn 500100
int tree[maxn];
int color;
int degree[maxn];//度数
typedef struct node
{
bool flag;
struct node *next[27];
int id;
node()
{
id = 0;
flag = false;
memset(next,0, sizeof(next));//将这个节点下一层的所有节点变成NULL,保证
//这时候没有新的节点。
}
}Trie;
int find(int x)
{
if (tree[x] != x)
tree[x] = find(tree[x]);
return tree[x];
}
void merge(int a, int b)
{
int fx = find(a), fy = find(b);
if (fx != fy)
tree[fx] = fy;
}
int insert(Trie *root,string word)//利用字典树来进行hash
{
Trie *p = root;
int i = 0;
while (word[i] != '\0')
{
int index = word[i] - 'a';
if (!p->next[index])
p->next[index] = new Trie;
p = p->next[index];
i++;
}
if (p->flag)
return p->id;
else
{
p->flag = true;
p->id = ++color;
return p->id;
}
}
void init()
{
for (int i = 0; i < maxn; i++)
tree[i] = i;
}
int main()
{
init();
string a, b;
Trie *root = new Trie;
while (cin >> a >> b)
{
int i = insert(root,a);
int j = insert(root,b);
degree[i]++;
degree[j]++;
merge(i, j);
}
int s = find(1);
int num = 0;//度为奇数的节点个数
for (int i = 1; i <= color; i++)
{
if (degree[i] % 2 == 1)
num++;
if (num > 2)
{
cout << "Impossible" << endl;
return 0;
}
if (find(i) != s)
{
cout << "Impossible" << endl;
return 0;
}
}
if (num == 1)
cout << "Impossible" << endl;
else
cout << "Possible" << endl;
return 0;
}
先写到这,去 洗个澡。。今天要 刷题!!【奋斗.jpg】
第四道:
noip 2013 货车运输
是个最大生成树边形 + 树上倍增 自己写的,除了 数组开小了wa了别的还是可以的
没啥可说的 ,知道这么做了就是应写代码了
领完提醒一点,最小生成树 还是单行边,这题的双向变得在 书确立了后加哦
#include
#include
#include
//by mars_ch
using namespace std;
int n,m;
int tot;
int cnt;
struct node
{
int f,t,z;
int nxt;
}e[100005];
int first[100005];
int f[100005];
int fa[100005][20];
int dis[10005][20];
int vis[100005];
int dep[100005];
int find(int x)
{
if(f[x] == x) return x;
f[x]=find(f[x]);
return f[x];
}
void add(int a,int b,int c)
{
e[tot].f=a;
e[tot].t=b;
e[tot].z=c;
e[tot].nxt=first[a];
first[a]=tot++;
}
struct data
{
int x,y,w;
}a[100005];
bool cmp(data a,data b)
{
return a.w>b.w;
}
void dfs(int a)
{
vis[a]=1;
for(int i=1;i<=16;i++)
{
fa[a][i]=fa[fa[a][i-1]][i-1];
dis[a][i]=min(dis[a][i-1],dis[fa[a][i-1]][i-1]);
}
for(int i=first[a];i!=-1;i=e[i].nxt)
{
if(vis[e[i].t]) continue;
fa[e[i].t][0]=a;
dis[e[i].t][0]=e[i].z;
dep[e[i].t]=dep[a]+1;
dfs(e[i].t);
}
}
int lca(int a,int b)
{
if(dep[a]for(int i=16;i!=-1;i--) //类似背包的拆分?
{
if(dep[a]>=dep[b]+(1<if(a == b) return b;
}
for(int i=16;i!=-1;i--)
{
if(fa[a][i]!=fa[b][i])
{
a=fa[a][i],b=fa[b][i];
}
}
return fa[a][0]; //注意return 的是fa【a】【0】 就是引进提到的a和b相同父亲的那个父亲。
}
int query(int a,int b)
{
int minn=999999;
int t=dep[a]-dep[b];
for(int i=0;i<=16;i++)
{
if(t&(1<//表示的是t的第i位是否为1
{
minn=min(minn,dis[a][i]);
a=fa[a][i];
}
}
return minn;
}
int main()
{
memset(first,-1,sizeof(first));
memset(dis,999999,sizeof(dis));
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
}
for(int i=1;i<=n;i++)
{
f[i]=i;
}
sort(a+1,a+m+1,cmp);
for(int i=1;i<=m;i++)
{
int ffa=find(a[i].x);
int ffb=find(a[i].y);
if(ffa!=ffb)
{
f[ffa]=ffb;
add(a[i].x,a[i].y,a[i].w);
add(a[i].y,a[i].x,a[i].w);
cnt++;
if(cnt==n-1) break;
}
}
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
dfs(i);
}
}
int q;
scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int a,b;
scanf("%d%d",&a,&b);
if(find(a)!=find(b))
{
puts("-1");
continue;
}
int jy=lca(a,b);
printf("%d\n",min(query(a,jy),query(b,jy)));
}
return 0;
}
第五道:
poj 2377 最大生成树的水题
但是因为没有看见判-1 wa了一次。。。
#include
#include
#include
//by mars_ch
using namespace std;
int n,m;
struct data
{
int x,y,w;
}e[20005];
int f[1005];
bool cmp(data a,data b)
{
return a.w>b.w;
}
int find(int x)
{
if(f[x] == x) return x;
f[x]=find(f[x]);
return f[x];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
}
for(int i=1;i<=n;i++)
{
f[i]=i;
}
int cnt=0;
int ans=0;
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++)
{
int fa=find(e[i].x);
int fb=find(e[i].y);
if(fa!=fb)
{
f[fa]=fb;
ans+=e[i].w;
cnt++;
if(cnt == n-1) break;
}
}
if(cnt!=n-1) puts("-1");
else printf("%d\n",ans);
return 0;
}
第六道:
最小生成树的裸题。。。
第七道:
poj 1734 实在是不想写了。。。。明天我补。。。。