【ASC45D】【构造】方法一之电阻网络法 WIKI Gambler's ruin
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<functional>
#include<string>
#include<algorithm>
#include<time.h>
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned int UI;
typedef int Int;
template <class T> inline void gmax(T &a,T b){if(b>a)a=b;}
template <class T> inline void gmin(T &a,T b){if(b<a)a=b;}
using namespace std;
const int N=0,M=0,L=0,Z=1e9+7,t30=1<<30,maxint=2147483647,ms31=522133279,ms63=1061109567,ms127=2139062143;
const double eps=1e-8,PI=acos(-1.0);//.0
struct A{};
map<int,int>mop;
int casenum,casei,inf;
int p,q;//概率为p/q
int a[105];
int b[105][2];
void fre()
{
freopen("drunkard.in","r",stdin);
freopen("drunkard.out","w",stdout);
}
int main()
{
fre();
while(~scanf("%d%d",&p,&q),p||q)
{
//n,p-1个中转点,1,q-p-1个中转点,n-1
//即q+1,[2,p],1,[p+1,p+q-p-1],q
printf("%d\n",q+1);
int m=0;
a[++m]=q+1;
for(int i=2;i<=p;i++)a[++m]=i;
a[++m]=1;
for(int i=p+1;i<=q;i++)a[++m]=i;
for(int i=2;i<m;i++)
{
b[a[i]][0]=a[i-1];
b[a[i]][1]=a[i+1];
}
for(int i=1;i<=m-2;i++)printf("%d %d\n",b[i][0],b[i][1]);
}
return 0;
}
/*
【题意】
一个醉汉在一个有向图上走。
该有向图有n个点,除了第n-1和第n个点,每个点都有两条出边,可以有重边,可以有自环。
我们从1点开始走,每次等概率选择两条出边中的一条走,走到n或者n-1就停下。
已知这个人走到n-1号点的概率是p/q,现在问你这个图可以是怎样的。
题目只告诉你p和q。
n以及1~n-2的每个点连出的边都是你自己定的。
[1<=p<q<=100],[1<=n<=1000]
【类型】
构造题,脑洞题
【分析】
我们想构造出p/q的概率,要既能恰好达成分母,又能恰好达成分子。
首先最基本的大概是一条链,每个点发出两条边都相同。
这样我们可以有50/100的概率到达n-1
比如1->2->3->4->
|
n-1
但是链结构的话,我们很难使得分母恰好符合要求。
于是我们可以考虑二叉树结构。
二叉树可以分出2^m个节点,使得2^m>=q。
但是这样要如何构成恰好的分数呢?比如1/3?
这时就知道先看样例的重要性了。样例中就恰好是1/3——
4<-1<->2->3
这里存在环结构,于是我们设想通过列方程求解。
我们设达到点x的概率为p[x],那么就有——
p[1]=1,
p[2]=0.5p[1]
p[1]=0.5p[2]
=========================================================
ICPC的大神告诉了我一种构造方法。
思想类似于电阻网络:
n,p-1个中转点,1,q-p-1个中转点,n-1
为什么这样构造是对的呢QwQ不太理解。
=========================================================
精度逼近法是否可以尝试呢?
【优化】
【trick】
【数据】
input
1 3
0 0
output
4
2 4
3 1
*/
【ASC45D】【构造】方法二之暴力冲精度法
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<functional>
#include<string>
#include<algorithm>
#include<time.h>
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned int UI;
typedef int Int;
template <class T> inline void gmax(T &a,T b){if(b>a)a=b;}
template <class T> inline void gmin(T &a,T b){if(b<a)a=b;}
using namespace std;
const int N=0,M=0,L=0,Z=1e9+7,t30=1<<30,maxint=2147483647,ms31=522133279,ms63=1061109567,ms127=2139062143;
int p,q;//概率为p/q
struct A
{
int l,r;
double u;
}a[1000];
void fre()
{
freopen("drunkard.in","r",stdin);
freopen("drunkard.out","w",stdout);
}
int main()
{
fre();
while(~scanf("%d%d",&p,&q),p||q)
{
double v=1.0*p/q;
double u=1;
for(int i=1;i<=998;i++)
{
a[i].l=i+1;//链上都是奇数点——1,3,5,7,9,...
a[i].r=1000;//结束点初始都设为n。
a[i].u=u=u/2;
}
for(int i=1;i<=998;i++)
{
if(v>=a[i].u)
{
a[i].r=999;
v-=a[i].u;
}
}
printf("%d\n",1000);
for(int i=1;i<=998;i++)
printf("%d %d\n",a[i].l,a[i].r);
}
return 0;
}
/*
【题意】
一个醉汉在一个有向图上走。
该有向图有n个点,除了第n-1和第n个点,每个点都有两条出边,可以有重边,可以有自环。
我们从1点开始走,每次等概率选择两条出边中的一条走,走到n或者n-1就停下。
已知这个人走到n-1号点的概率是p/q,现在问你这个图可以是怎样的。
题目只告诉你p和q。
n以及1~n-2的每个点连出的边都是你自己定的。
[1<=p<q<=100],[1<=n<=1000]
【类型】
构造题,脑洞题
【分析】
我们想构造出p/q的概率,要既能恰好达成分母,又能恰好达成分子。
首先最基本的大概是一条链,每个点发出两条边都相同。
这样我们可以有50/100的概率到达n-1
比如1->2->3->4->
|
n-1
但是链结构的话,我们很难使得分母恰好符合要求。
于是我们可以考虑二叉树结构。
二叉树可以分出2^m个节点,使得2^m>=q。
但是这样要如何构成恰好的分数呢?比如1/3?
这时就知道先看样例的重要性了。样例中就恰好是1/3——
4<-1<->2->3
这里存在环结构,于是我们设想通过列方程求解。
我们设达到点x的概率为p[x],那么就有——
p[1]=1,
p[2]=0.5p[1]
p[1]=0.5p[2]
=========================================================
ICPC的大神告诉了我一种构造方法。
思想类似于电阻网络:
n,p-1个中转点,1,q-p-1个中转点,n-1
为什么这样构造是对的呢QwQ不太理解。
=========================================================
精度逼近法是否可以尝试呢?
竟然也AC啦!
果然有时候大力出奇迹啊!出题人还是普遍懒啊!
【优化】
【trick】
【数据】
input
1 3
0 0
output
4
2 4
3 1
*/
【ASC45D】【构造】方法三之比例转换法
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<ctype.h>
#include<math.h>
#include<map>
#include<set>
#include<vector>
#include<queue>
#include<functional>
#include<string>
#include<algorithm>
#include<time.h>
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned int UI;
typedef int Int;
template <class T> inline void gmax(T &a,T b){if(b>a)a=b;}
template <class T> inline void gmin(T &a,T b){if(b<a)a=b;}
using namespace std;
const int N=0,M=0,L=0,Z=1e9+7,t30=1<<30,maxint=2147483647,ms31=522133279,ms63=1061109567,ms127=2139062143;
int p,q;//概率为p/q
struct A
{
int l,r,u;
}a[20];
void fre()
{
freopen("drunkard.in","r",stdin);
freopen("drunkard.out","w",stdout);
}
int main()
{
fre();
while(~scanf("%d%d",&p,&q),p||q)
{
q=q-p;
a[1].l=2;a[1].r=9;
for(int i=2,u=128;i<=8;i++)
{
a[i].l=i+1;
a[i].r=1;
a[i].u=u=u>>1;
}a[8].l=1;
for(int i=9,u=128;i<=15;i++)
{
a[i].l=i+1;
a[i].r=1;
a[i].u=u=u>>1;
}a[15].l=1;
for(int i=2;i<=8;i++)
{
if(p>=a[i].u)
{
a[i].r=16;
p-=a[i].u;
}
}
for(int i=9;i<=15;i++)
{
if(q>=a[i].u)
{
a[i].r=17;
q-=a[i].u;
}
}
printf("17\n");
for(int i=1;i<=15;i++)printf("%d %d\n",a[i].l,a[i].r);
}
return 0;
}
/*
【题意】
一个醉汉在一个有向图上走。
该有向图有n个点,除了第n-1和第n个点,每个点都有两条出边,可以有重边,可以有自环。
我们从1点开始走,每次等概率选择两条出边中的一条走,走到n或者n-1就停下。
已知这个人走到n-1号点的概率是p/q,现在问你这个图可以是怎样的。
题目只告诉你p和q。
n以及1~n-2的每个点连出的边都是你自己定的。
[1<=p<q<=100],[1<=n<=1000]
【类型】
构造题,脑洞题
【分析】
我们想构造出p/q的概率,要既能恰好达成分母,又能恰好达成分子。
首先最基本的大概是一条链,每个点发出两条边都相同。
这样我们可以有50/100的概率到达n-1
比如1->2->3->4->
|
n-1
但是链结构的话,我们很难使得分母恰好符合要求。
于是我们可以考虑二叉树结构。
二叉树可以分出2^m个节点,使得2^m>=q。
但是这样要如何构成恰好的分数呢?比如1/3?
这时就知道先看样例的重要性了。样例中就恰好是1/3——
4<-1<->2->3
这里存在环结构,于是我们设想通过列方程求解。
我们设达到点x的概率为p[x],那么就有——
p[1]=1,
p[2]=0.5p[1]
p[1]=0.5p[2]
=========================================================
ICPC的大神告诉了我一种构造方法。
思想类似于电阻网络:
n,p-1个中转点,1,q-p-1个中转点,n-1
为什么这样构造是对的呢QwQ不太理解。
=========================================================
精度逼近法是否可以尝试呢?
竟然也AC啦!
果然有时候大力出奇迹啊!出题人还是普遍懒啊!
=========================================================
这题还有另外一种做法,就是比例转换法。
我们想,如果是有p/2^k流向了n-1节点,有(q-p)/2^k流向了n节点,有(2^k-q)/2^k的流回根。答案肯定也可以。
于是做法是,依然构建一个二叉树结构的图。
root
| |
2 9
3 10
4 11
5 12
6 13
7 14
8 15
16形成自环,表示dead节点
17=n-1和18=n是需要流向的节点
左子树向n-1流动,右子树向n流动
对于每个子树,都可以流出1/4,1/8,...,1/2^k的流量。
如果k达到了256,我们就可以凑出(1~127)/256的比例是流向n-1的,使得分子恰好为p即可
同理,我们凑出q/256的比例是流向n
但是这样,走到n-1点的概率依旧是p/256,我们要消分母。
如果消除分母呢?我们把多余的流量流回根。
这样对于一个从根部开始展开的决策,能流出流量的概率就恰好是q/256,然后其中有(p-q)/q流向了n-1
于是这个构造方法可以AC这道题。
【优化】
【trick】
【数据】
input
1 3
0
output
4
2 4
3 1
*/